IO流
输入流和输出流
Java中的IO流根据功能划分为:输入流和输出流。输入流:用于读取数据。输出流:用于写出数据。输入输出的参照方向是根据我们的程序的。
字节流和字符流
Java中的IO流根据处理的单位划分为:字节流和字符流。字节流:以字节为单位读写数据。字符流:以字符为单位读写数据。
高级流和低级流
Java中的IO流还分为:高级流和低级流。高级流:不能独立存在,必须基于另一个流工作。低级流:数据有明确的来源或者去向
字节流和字符流
字节流
InputStream:抽象类,是所有字节输入流的父类。
OutputStream:抽象类,是所有字节输出流的父类。
字符流
Reader与Writer 带有缓冲区。
Reader:抽象类,所有字符输入流的父类,不能实例化
Writer:抽象类,所有字符输出流的父类,不能实例化
字符流处理单位为字符:一次处理一个字符unicode。字符流本质上还是读写字节。
FIS和FOS
用于读写文件的流。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(); } }
BIS和BOS
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方法没有任何作用 } }
DIS和DOS
方便读写基本数据类型,但是效率不高,和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();
ISR和OSW
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();
BR和BW
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();
FileWriter和FileReader
可以直接读写文本文件的字符流。比较方便。但是使用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方法。
OOS和OIS
将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(); } }