文件(2)--IO流

IO


输入流和输出流

Java中的IO流根据功能划分为:输入流和输出流。输入流:用于读取数据。输出流:用于写出数据。输入输出的参照方向是根据我们的程序的。

字节流和字符流

Java中的IO流根据处理的单位划分为:字节流和字符流。字节流:以字节为单位读写数据。字符流:以字符为单位读写数据。

高级流和低级流

Java中的IO流还分为:高级流和低级流。高级流:不能独立存在,必须基于另一个流工作。低级流:数据有明确的来源或者去向

字节流和字符流


字节流

InputStream:抽象类,是所有字节输入流的父类。

OutputStream:抽象类,是所有字节输出流的父类。

字符流

Reader与Writer 带有缓冲区。

Reader:抽象类,所有字符输入流的父类,不能实例化

Writer:抽象类,所有字符输出流的父类,不能实例化

字符流处理单位为字符:一次处理一个字符unicode。字符流本质上还是读写字节。

FISFOS


用于读写文件的流。FileInputStream:文件字节输入流,是低级流。FileOutputStream:文件字节输出流,是低级流。

FileOutputStream

构造器:

FileOutputStream(String name) 根据文件名创建用于写该文件的输出流。

FileOutputStream(File file)

FileOutputStream(File file, boolean append) append - 如果为 true,则将字节写入文件末尾处,而不是写入文件开始处。

如果文件不存在,会自动创建该文件。

方法:

void write(int   d)写一个字节,写给定的int值的”低八位”

void write(byte[] d)将给定的字节数组中的所有字节一次性写出

void write(byte[] d, int start,int len)从下标start开始,写len个字节。

FileOutputStream

构造器:

FileOutputStream(File file)

FileOutputStream(String name)当前目录是相对于根目录下的

FileOutputStream(String name, boolean append)

方法:

int read() 读取1个字节,8位

int read(byte[] b) 从此输入流中将最多 b.length 个字节的数据读入 b 中

int read(byte[] b, int off, int len)

从输入流中将最多 len 个字节的数据读入一个 byte 数组中。从off处开始放

long skip(long n) 从输入流中跳过并丢弃 n 个字节的数据。

public class TestFile {
    public static void main(String[] args) throws Exception {
        OutputStream out = null;
        try{
            out = new FileOutputStream("test.txt");
            out.write(1);
            out.write('A');
            byte[] bytes = "大家好".getBytes("utf-8");
            out.write(bytes.length);
            out.write(bytes);
        }
        catch(Exception e){
        }
        finally{
            if(out != null){
                try{
                    out.close();
                }
                catch(IOException e){
                }
            }
        }
    }
}

public class TestFile {
    public static void main(String[] args) throws Exception {
        InputStream in = null;
        try{
            in = new FileInputStream("test.txt");
            System.out.println(in.read());// 1
            System.out.println((char)in.read());// 'A'
            int len = in.read();
            byte[] bytes = new byte[len];
            in.read(bytes);
            String str = new String(bytes, "utf-8");
            System.out.println(str);
        }
        catch(Exception e){
        }
        finally{
            if(in != null){
                try{
                    in.close();
                }
                catch(IOException e){
                }
            }
        }
    }
}

复制文件

public class TestFile {
    public static void main(String[] args) throws Exception {
        FileInputStream fis = new FileInputStream("E:\代码整体规范.pptx");
        FileOutputStream fos = new FileOutputStream("E:\代码整体规范222.pptx");
        byte[] buffer = new byte[1024 * 10];// 10k
        int len = -1;
        while((len = fis.read(buffer)) != -1){
            fos.write(buffer, 0, len);
        }
        fis.close();
        fos.close();
    }
}

BISBOS


BufferedInputStream:缓冲字节输入流

BufferedOutputStream:缓冲字节输出流

缓冲流的功能:内部维护一个缓冲区,用于减少读写次数,提高读写效率。

BufferedOutputStream

原理:BufferedOutputStream内部有一个缓冲区,大小8192k,每次调用write方法的时候,它首先把数据放入缓冲区中,等缓冲区存满后,调用方法out.write(buf,0,count)把缓冲区中的内容写出。这样提高的写的效率,不是一个字节一个字节的写。

构造器:

BufferedOutputStream(OutputStream out) 

BufferedOutputStream(OutputStream out, int size) size:指定缓冲区大小

方法:

void flush() 刷新此缓冲的输出流。

void write(byte[] b, int off, int len)

void write(int b) 

   BufferedInputStream

原理:

BufferedInputStream内部有一个缓冲区,默认大小为8M,每次调用read方法的时候,它首先尝试从缓冲区里读取数据,若读取失败(缓冲区无可读数据),则选择从物理数据源(譬如文件)读取新数据(这里会尝试尽可能读取多的字节)放入到缓冲区中,最后再将缓冲区中的内容部分或全部返回给用户.由于从缓冲区里读取数据远比直接从物理数据源(譬如文件)读取速度快,所以BufferedInputStream的效率很高!

构造器:

BufferedInputStream(InputStream in)

BufferedInputStream(InputStream in, int size) size指的是缓冲区大小

方法:

read()

int read(byte[] b, int off, int len)

复制文件

public class TestFile {
    public static void main(String[] args) throws Exception {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.zip"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b"));
        int d = -1;
        // bis和bos内部都维护了一个缓冲数组,(8192)
        while((d = bis.read()) != -1){// read方法一次性读取多个字节放入缓冲区中
            bos.write(d);// 把读到的字节放入缓冲数组中,数组装满了,再一次性写出
        }
        bis.close();
        bos.close();
    }
}

flush方法

public class TestFile {
    public static void main(String[] args) throws Exception {
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));
        bos.write("大家好".getBytes("utf-8"));
        // 没有真正写出,而是放入缓冲区中.等缓冲区满了才写出
        bos.flush();// 把缓冲数组中的数据全部写出。
        bos.close();// 先调用flush()方法后再关闭。所以最后一定要关闭,否则可能会丢数据
        // 一般有缓冲区的flush方法有效,没有缓冲区的flush方法没有任何作用
    }
}

DISDOS


方便读写基本数据类型,但是效率不高,和RandomaccessFile的功能相似。

DataInputStream:可以方便的读取基本类型数据

DataOutputStream:可以方便的写出基本类型数据

DataOutputStream

构造器:DataOutputStream(OutputStream out),传入低级流,如FileOutputStream

方法:

  size()   返回即到目前为止写入此数据输出流的字节数。

  void write(byte[] b, int off, int len)

  void write(int b) 将指定字节(参数 b 的八个低位)写入基础输出流。

  void writeBoolean(boolean v)

  void writeChar(int v)

  void writeDouble(double v)

  void writeFloat(float v)

  void writeInt(int v)

  void writeLong(long v)

  void writeShort(int v)

  void writeUTF(String str)

   DataInputStream

构造器:

DataInputStream(InputStream in) ,传入低级流,如FileInputStream

方法:

 int read(byte[] b)

 int read(byte[] b, int off, int len) 

 boolean readBoolean()

 char readChar()

 double readDouble()

 float readFloat()

 int readInt()

 long readLong()

 short readShort()

 String readUTF()

 int skipBytes(int n)

DataOutputStream dos = new DataOutputStream(new FileOutputStream("dos.txt"));
dos.writeInt(1000);
dos.writeLong(34l);
dos.writeDouble(2.34);
dos.writeUTF("你好");
dos.close();

DataInputStream dis=new DataInputStream(new FileInputStream("dos.txt"));
System.out.println(dis.readInt());
System.out.println(dis.readLong());
System.out.println(dis.readDouble());
System.out.println(dis.readUTF());
dis.close();

高级流的组合使用

我们既要可以方便的写出基本数据类型,又要写的效率高,那么我们可以联合使用DOS、BOS

FileOutputStream fos = new FileOutputStream("a.txt");
// 首先,为了提高些效率,包装为缓冲流。
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 为了方便的写出基本类型数据,包转为DOS
DataOutputStream dos = new DataOutputStream(bos);
// dos既可以方便的写出基本类型数据,又提高了效率
dos.writeInt(1234);
dos.close();

ISROSW


InputStreamReader: 字符输入流  OutputStreamWriter:字符输出流

OutputStreamWriter

构造器:

OutputStreamWriter(OutputStream out) ,使用默认字符编码,平台默认的编码 window默认是gbk,liunx默认是utf-8

OutputStreamWriter(OutputStream out, String charsetName) 使用指定字符编码 

方法:

void  write(int c)               写入单个字符,即c的低16位

void  write(char[] cbuf)             一次性将给定的字符数组中的所有字符写出

void  write(char[] cbuf, int off, int len) 从start处开始连续将len字符写出

void  write(String str)

void  write(String str, int off, int len) 写入字符串的某一部分。   

String getEncoding()            返回此流使用的字符编码的名称。

InputStreamReader

构造器:

InputStreamReader(InputStream in)

InputStreamReader(InputStream in, String charsetName)

方法:

String getEncoding()   返回此流使用的字符编码的名称。

int read()     读取单个字符。以int值形式返回,该int值”低16位”有效。如果是utf-8编码方案,会一个一个匹配,先读一个字符如果是英文字符,进行编码。不是英文字符则再读一个字符,中文字符占3个字符, 会一次性读取3个字符,把它按照utf-8解码成字符,再以unicode编码存在char中。

int read(char[] c)  一次最多尝试读取给定数组的length个字符,并存入数组返回值为实际读取到的字符

int read(char[] cbuf, int offset, int length)

OutputStreamWriter osw=new OutputStreamWriter(System.out);//写到控制台
osw.write(123);
osw.write(new char[]{'A','B'});
osw.write("大家好!");
System.out.println(osw.getEncoding());
osw.close();

InputStreamReader reader=new InputStreamReader(new FileInputStream("b.txt"));
int c=-1;
while((c=reader.read())!=-1){
       char chs=(char)c;
       System.out.print(chs);
}
reader.close();

从控制台读

InputStreamReader reader=new InputStreamReader(System.in);
char[] chs=new char[3];
reader.read(chs);//阻塞方法,如果控制台没有数据会等待控制台输入
System.out.println(Arrays.toString(chs));
reader.close();

复制”文本文件”

只能复制文本文件,不是什么文件都能复制的

InputStreamReader reader=new InputStreamReader(new FileInputStream("src"+File.separator+"demo"+File.separator+"Demo01.java"));
OutputStreamWriter writer=new OutputStreamWriter(new FileOutputStream("E:\a.java"));
char[] chs=new char[1024*10];
int len=-1;
while((len=reader.read(chs))!=-1){
    writer.write(chs, 0, len);
}
reader.close();
writer.close();

BRBW


BufferedReader:缓冲字符输入流

BufferedWriter:缓冲字符输出流

可以实现按行读取。

BufferedWriter

构造器:

BufferedWriter(Writer out) 传入一个字符流

BufferedWriter(Writer out, int size)传入一个字符流,size指的是缓冲区大小

方法:

 void flush()

 void newLine() 写入一个行分隔符。

 void write(int c) 写入单个字符。

 void write(char[] chs)

 void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。

 void write(String str)

 void write(String s, int off, int len) 写入字符串的某一部分。

BufferedReader

构造器:

BufferedReader(Reader in)

BufferedReader(Reader in, int sz)

方法:

 int read() 读取单个字符。

 int read(char[] chs)

 int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。

 String readLine() 读取一个文本行。

案例

BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt"),"utf-8"));
writer.write("你好!");
writer.newLine();
writer.write("你好!");
writer.newLine();
writer.close();

BufferedReader reader=new BufferedReader(new InputStreamReader(new FileInputStream("a.txt"),"utf-8"));
String str=null;
while((str=reader.readLine())!=null){
    System.out.println(str);
}
reader.close();

或者

BufferedReader reader=new BufferedReader(new InputStreamReader(new FileInputStream("a.txt"),"utf-8"));
char[] chs=new char[5];
int len=-1;
while((len=reader.read(chs))!=-1){
    System.out.print(new String(chs));
}
reader.close();

复制文件

BufferedReader reader=new BufferedReader(new InputStreamReader(new FileInputStream("src/demo/Demo01.java"),"gbk"));
BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("E:\a.java"),"gbk"));
String line=null;
while((line=reader.readLine())!=null){
    writer.write(line);
    writer.newLine();
}
reader.close();
writer.close();

读取控制台中的数据,复制到文本文件中

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt")));
String str=null;
while(true){
    str=reader.readLine();
    if(str!=null&&str.equals("bye")){
        break;
    }
    writer.write(str);
    writer.newLine();
}
reader.close();
writer.close();

FileWriterFileReader


可以直接读写文本文件的字符流。比较方便。但是使用FileWriter和FileReader就默认使用了当前系统默认的字符集进行读写。不能自己设置字符集,所以用的不是太多。

FileWriter extends OutputStreamWriter

构造器:

FileWriter(File file)

FileWriter(File file, boolean append)

FileWriter(String fileName)

FileWriter(String fileName, boolean append)

构造方法实现

public FileWriter(String fileName) throws IOException {
    super(new FileOutputStream(fileName));
}
//即new FileWriter(“a.txt”)完全相当于new OutputStreamWriter(new FileOutputStream(a.txt))

方法:全部继承于OutputStreamWriter。

FileReader extends InputStreamReader

构造器:

FileReader(File file)

FileReader(String fileName)

public FileReader(String fileName) throws FileNotFoundException {
    super(new FileInputStream(fileName));
}
//即new FileReader(“a.txt”)完全相当于new InputStreamReader(new FileInputSteam(“a.txt”))

方法:全部继承于InputStreamReader

FileWriter writer=new FileWriter("a.txt");
writer.write("你好");
//变成缓冲字符流
BufferedWriter br=new BufferedWriter(writer);
br.write("%%%");
br.close();

FileReader reader=new FileReader("a.txt");
int c=-1;
while((c=reader.read())!=-1){
    System.out.println((char)c);
}
reader.close();

PrintWriter


缓冲字符输出流。在写文件时,可以指定字符集,比较方便。

构造器:

PrintWriter(File file)                          

PrintWriter(File file, String charset)    

PrintWriter(String fileName)

PrintWriter(String fileName, String charset)

PrintWriter(OutputStream out)           

PrintWriter(OutputStream out, boolean autoFlush) 自动刷新

创建带有自动刷新的缓冲字符输出流,每当调用"pringln()"注意是带有ln方法。就会在写操作后自动调用flush()方法,即自动刷新

PrintWriter(Writer out)

PrintWriter(Writer out, boolean autoFlush)

//该构造器既能指定字符集也能指定自动刷新

方法:

void print();输出,不带换行符,和System.out.print()差不多

void println() 带换行符

void write(char[] buf)

void write(char[] buf, int off, int len)

void write(int c)

void write(String s)

void write(String s, int off, int len)

案例

PrintWriter pw=new PrintWriter("p.txt","utf-8");
pw.println(true);
pw.println(1234567);
pw.println("你好!");
//注意,写入文件中的是字符串,true,1234567,你好
pw.close();

Serializable接口


public interface Serializable类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。

序列化接口没有方法或字段,仅用于标识可序列化的语义。

transient关键字

transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象呗串行化的时候,transient型的便利的值不包括再串行化的表示中,然而非transient型的变量是被包括进去的。

Transient修饰的属性可以通过其它手段进行序列化,可以参考ArrayList源码,ArrayList中底层数组是用transient修饰,但是进行了序列化。因为重写了readObject和writeObject方法。

OOSOIS


将Object对象转换为byte序列,就是序列化,反之叫反序列化。

ObjectOutputStream:对象输出流

ObjectInputStream:对象输入流

ObjectOutputStream

构造器:ObjectOutputStream(OutputStream out)

方法:void writeObject(Object obj) 线程安全的方法

ObjectInputStream

构造器:ObjectInputStream(InputStream in) 

方法:readObject()   线程安全的方法

public class Person implements Serializable {
    private String name;
    private int age;
    private int sex;
    private transient String info;
    private List<String> otherInfo;     
    //...get/set方法 equals方法 hashcode方法
}

读写

public class Test {
    public static void main(String[] args) throws Exception {
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("a.txt"));
        List<String> list = new ArrayList<String>();
        list.add("一");
        list.add("二");
        list.add("三");
        Person p = new Person("zhansgan", 22, 1, "男", list);
        // 将p的name、age、sex、otherInfo值转换成二进制写入文件
        // 比如name=zhangsan, 取’z’二进制为:1111010写入只有在写字符串时才有编码格式问题
        out.writeObject(p);
        out.close();
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("a.txt"));
        Person p1 = (Person)in.readObject();
        System.out.println(p1);// info值是null,没有被序列化
        System.out.println(p1.equals(p));
        in.close();
    }
}
原文地址:https://www.cnblogs.com/qin-derella/p/6647285.html