IO流
IO流:存储和读取数据的解决方案,用于读写文件里的数据(可以读写文件、或者是网络中的数据…)
I:input O:output
流:像水流一样传输数据
IO流按照流向可以分为输出流和输入流:
输出流:程序->文件
输入流:文件->程序
按照操作文件的类型可以分为字节流和字符流:
字节流:可以操作所有类型的文件
字符流:只能操作纯文本文件
字节流
FileOutputStream
操作本地文件的字节输出流,可以把程序中的数据写到本地文件中。
字节输出流基本用法及步骤:
//创建字节输出对象
细节一:参数为文件路径或者File对象都可以
细节二:如果文件不存在,会创建一个新的文件,前提是父路径存在。
细节三:如果文件存在,则会清空文件
FileOutputStream fos = new FileOutputStream("文件路径");
//写入内容
细节:write方法的参数是整数,但是写到本地文件中的内容是ASCII码上对应的字符。
fos.write(97);
//释放资源
fos.close();
写数据的三种方式
void write(int b );//一次写一个字节数据
void write(byte[] b);//一次写一个字节数组数据,可以使用String中的getBytes()方法快速得到byte数组
void write(byte[] b,int off,int len);//一次写一个字节数组的部分内容(off表示起始索引,len表示个数)
换行和续写操作:
换行:
再次写出一个换行符即可。
Windows:\r\n
Linux: \n.
Mac: \r。
细节:
在Windows操作系统中,Java对回车换行进行了优化。
虽然完整的是\n\r,但是是要使用其中一个即可
Java会底层自动补全。
建议:
不要省略,写全了。
续写:
如果想要续写,打开续写开关即可,
开关位置:创建对象的第二个参数
默认false:表示关闭续写,此时创建对象会清空文件
手动传递true,表示此时创建对象不会清空问价。
FIleInputStream
操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中。
字节输入流基本操作及细节:
//创建对象
细节:
如果文件不存在,就直接报错。
FileInputStream fis = new FileInputStream("文件路径");
//读取
细节1:
一次读一个字节,读出来的是数据的ASCII码
细节2:
读到文件末了,read返回-1.
int a = fis.read();
System.out.println(a);
//释放资源
细节:
每次使用完流后都要释放资源
fis.close();
循环读取:
FileInputStream fis = new FileInputStream("文件路径");
int b;
while((b = fis.read)!= -1){
System.out.print(b);
}
简单拷贝操作:
1、创建对象
FileIntputStream fis = new FileIntputStream("原文件路径");
FileOutputStream fos = new FileOutputStream("拷贝文件路径");
2、拷贝
核心思想:边读边写
int b;
while((b = fis.read())!=-1){
fos.wirte(b);
}
3、释放资源
先开的最关闭
fos.close();
fis.close();
//弊端:一次只读一个字节,效率太低,耗时太久。
FileInputStream读取方法
public int read();//一次读一个字节数据
public int read(Byte[] buffer);//一次读一个字节数组数据,每次读取会尽可能把数组装满,数组长度尽量为1024的整数倍
文件拷贝改写:
1、创建对象
FileIntputStream fis = new FileIntputStream("原文件路径");
FileOutputStream fos = new FileOutputStream("拷贝文件路径");
2、拷贝
核心思想:边读边写
Byte[] b = new Byte[1024*1024*5];
int len;
while((len = fis.read(b))!=-1){
fos.wirte(b,0,len);
}
3、释放资源
先开的最关闭
fos.close();
fis.close();
计算机的存储规则(汉字)(GBK):
1、在计算机中,任意数据都是以二进制的形式存储的
2、计算机中最小的存储单元是一个字节
3、ASCII字符集中,一个英文占一个字节
4、简体中文版Windows,默认使用GBK字符集
5、GBK字符集完全兼容ASCII字符集
一个英文占一个字节,二进制第一位是0
一个中文占两个字节,二进制高位字节的第一位是1
Unicode
Unicode字符集的UTF-8编码格式
·一个英文占一个字节,二进制第一位是0,转成十进制是正数
·一个中文占三个字节,二进制第一位是1,第一个字节转成十进制是负数
注意:UTF-8不是字符集,而是编码规范
如何不产生乱码:
1、不要用字节流读取文本文件
2、编码解码时使用同一个码表,同一个编码方式
Java中编码的方法:
public byte[] getBytes();//使用默认方式进行编码
public byte[] getBytes(String charseName);//使用指定方式进行编码
Java中解码的方法:
String(byte[] bytes);//使用默认方式进行解码
String(byte[] bytes,charseName);//使用指定方法进行解码
字符流
字符流的底层是字节流
字符流 = 字节流+字符集
特点:
输入流:一次读一个字节,遇到中文时,一次读多个字节
输出流:底层会把数据按照指定的编译方式进行编译,再变成字节写到文件中
使用场景:对于纯文本文件的读取操作
FileReader
1、创建字符输入流对象
public FileReader(File file);//创建字符输入流关联本地文件
public FileReader(String pathname);//创建字符输入流关联本地文件
如果文件不存在直接报错
2、读取数据
public int read();//读取数据,读到末尾返回-1
public int read(byte[] buffer);//读取多个数据,读到末尾返回-1 带参=空参+强制类型转换
按字节流进行读取,读到中文,一次读多个字节,读取后解码,返回一个整数
读到文件末尾了,read方法返回-1
3、释放资源
public int close();//释放资源/关流
FileWrite
构造方法:
public FileWrite(File file);//创建字符输出流对象关联本地文件
public FileWrite(String pathname);//创建字符输出流对象关联本地文件
public FileWrite(File file,boolean append);//创建字符输出流对象关联本地文件,续写
public FileWrite(String pathname,boolean append);//创建字符输出流对象关联本地文件,续写
成员方法:
void write(int c);//写出一个字符
void write(String str);//写出一个字符串
void write(String str,int off,int len);//写出一个字符串的一部分
void write(char[] cbuf);//写出一个字符数组
void write(char[] cbuf,int off,int len);//写出一个字符数组的一部分
字符流原理解析
输入流:
1、创建字符流输入对象
底层:关联文件,并创建缓冲区(长度为8192的字节数组);
2、读取数据
底层:
1、判断缓冲区中是否有数据可以读取
2、缓冲区没有数据:就从文件中读取数据,装到缓冲区中,每次尽可能装满缓冲区,如果文件中也没有数据了,返回-1
3、缓冲区中有数据:就从缓冲区中读取,
空参的read方法:一次读取一个字节,遇到中文一次读多个字节,把字节解码并转为十进制返回
有参的read方法:把读取字节、解码、强转三步合并了,强制之后的字符放到数组中
输出流:
public void flush();//将缓冲区中的内容刷新进本地文件中
缓冲流
缓冲流提高性能的原因
·缓冲流自带长度为8192的缓冲区
·可以显著提高字节流的读写功能
·对字符流提高不明显,对字符缓冲流而言的关键点是两个独有方法
字节缓冲流
原理:底层自带了长度为8192的缓冲区提高性能
方法:
public BufferedinputStream(InputStream is);//把基本流包装成高级流,提高读取的效率
public BufferedOutputStream(InputStream is);//把基本流包装成高级流,提高写出的效率
字符缓冲流
原理:底层自带了长度为8192的缓冲区提高性能
public BufferedReader(Reader r);//把基本流变为高级流
public BufferedWriter(Writer w);//把基本流变为高级流
//特有方法
public String readLine();//读取一行数据,如果没有数据可读了,返回null,但是不会读取换行
public void newLine();//跨平台的换行
转换流
是字节流与字符流的桥梁
作用:
·字符转换输入流:InputStreamReader(字节输入流对象)
·字符转换输入流:OutputStreamReader(字节输出流对象)
1、指定字符集读写(已经淘汰)
2、字节流想要使用字符流的方法
序列化流/对象输出操作流
可以把Java中的对象写道本地文件中
构造方法:
public ObjectOutputStream(OutputStream out);//把基本流包装成高级流
成员方法:
public final void writeObject(Object obj);//把对象序列化(写出)到本地文件中去
小细节:
//使用对象输出流 将对象保存到文件中时会出现NotSerializableException异常
解决方案:需要让JavaBean类实现serializable接口
serializable中没有抽象方法,是标记性接口
一旦实现这个接口,就表示该类可以被序列化
反序列化流/对象输入操作流
可以把序列化到本地文件中的对象,读取到程序中来
构造方法:
public ObjectInputStream(InputStream out);//把基本流包装为高级流
成员方法:
public Object readObject();// 把序列化到本地文件中的对象,读取到程序中来
细节:需要注意给要序列化的对象进行版本号定义,否则当JavaBean中成员改变时,反序列化时会报错,抛出InvalidClassException异常
例:
private static final long serialVersionUID = -427553587245757343L;//此数据是由IDEA自动生成
//方法:
点击File->点击Settings->在最上面搜索serializable->选择serializable class without 'serialVersionUID'和Transient filed is not initialized on deserialization->点击OK,然后类名会有深色背景,点击,Alt+回车即可
如果类中某个成员不想序列化到本地文件,在该成员数据类型前嘉盛transient关键字即可
存储多个对象时,建议把他们放到集合中,再将集合序列化到本地文件
打印流
分类:打印流一般是指PrintStream和PrintWrite两类
特点:
1、打印流只操作文件的目的地,不操作数据源(只能写,不能读)
2、特有的写出方法可以实现,数据的原样写出
3、特有的写出方法可以实现自动刷新,自动换行,打印一次数据 = 写出 + 换行+刷新
字节打印流
构造方法:
public PrintStream(OutputStream/File/String);//关联字节输出流/文件/文件路径
public PrintStream(String fileName,Charset charset);//指定字符编码
public PrintStream(OutputStream out, boolean autoFlush);//默认自动刷新,字节流底层没有缓冲区,开不开自动刷新都一样
public PrintStream(OutputStream out, boolean autoFlush,String encoding);//指定字符编码并自动刷新
成员方法:
public void write(int b);//常规方法,将指定字节写出
public void println(Xxx xxx);//特有方法:打印任意数据,自动刷新,自动换行
public void print(Xxx xxx);//特有方法:打印任意数据,不换行
public void printf(String format,Object ...args);//特有方法:带有占位符的打印语句,不换行
字符打印流
构造方法:
public PrintStream(Write/File/String);//关联字符输出流/文件/文件路径
public PrintStream(String fileName,Charset charset);//指定字符编码
public PrintStream(OutputStream out, boolean autoFlush);//自动刷新,字符流有缓冲区,需要手动开启自动刷新
public PrintStream(OutputStream out, boolean autoFlush,String encoding);//指定字符编码并自动刷新
成员方法:
public void write(int b);//常规方法,将指定字节写出
public void println(Xxx xxx);//特有方法:打印任意数据,自动刷新,自动换行
public void print(Xxx xxx);//特有方法:打印任意数据,不换行
public void printf(String format,Object ...args);//特有方法:带有占位符的打印语句,不换行
解压缩流
解压的本质是把压缩包中的文件读取出来,按层级拷贝到目的地
方法:
public ZipInputStream(FileInputStream is);//创建解压流
public ZipEntry(Entry e);//创建Entry对象接收压缩包里的内容,压缩包里的内容以Entry的形式读取
public boolean toDirectory();//判断entry是否是文件夹
public Entry getNextEntry();//读取解压流中的entry对象
压缩流
方法:
public ZipOutputStream(FileOutputStream is);//创建压缩流
public putNextEntry(Entry e);//将Entry对象放到压缩流中