IO的分类及字节输出流
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
IO流:就是对数据存储和取出做操作
I:input 输入流
O:output 输出流
IO的分类:
流向:(以java程序为中心)
输入流 读取数据
输出流 写出数据
数据类型:
字节流: Java提供的顶层父类:
字节输入流 读取数据 InputStream
字节输出流 写出数据 OutputStream
字符流:
字符输入流 读取数据 Reader
字符输出流 写出数据 Writer
怎么区分使用字节流还是字符流呢?使用windows自带的记事本打开,如果你能看懂
就用字符流,如果你看不懂就用字节流。其实,字节流可以读取任何数据。
如果不知道用什么,就用字节流。
需求:往文件中写入一句话:"大数据,yyds"
分析:
1、这个操作最好用字符流,但是,今天我们只说字节流,字符流是基于字节流之后出现的
所以今天暂时用字节流了
2、因为我们需要往文件中写一句话,所以用输出流,字节输出流
经过上面的分析,我们最后采用的是,OutputStream
通过观察API发现,OutputStream这个类是一个抽象类,而抽象类不能被实例化
要想实例化,我们就必须找到一个具体的实现子类:FileOutputStream
FileOutputStream的构造方法
FileOutputStream(File file) 创建文件输出流以写入由指定的 File对象表示的文件。
FileOutputStream(String name) 创建文件输出流以指定的名称写入文件。
字节流写数据的步骤:
1、创建文件字节输出流对象
2、写数据
3、释放资源
*/
public class FileOutputStreamDemo1 {
public static void main(String[] args) throws IOException {//在这里抛出运行时期异常
//第一种构造方法创建对象
//创建文件字节输出流对象
//FileOutputStream(File file)
//如果文件不存在,就会自动创建
//如果这里创建对象的时候,传入的文件名不加盘符
//默认会在当前项目中创建
// File file = new File("a.txt");
//这里将来可能会报错,会有编译时期异常
// FileOutputStream fos = new FileOutputStream(file);
//第二种构造方法创建对象
//FileOutputStream(String name)
//如果文件不存在,就会自动创建
//如果这里创建对象的时候,传入的文件名不加盘符
//默认会在当前项目中创建
FileOutputStream fos = new FileOutputStream("b.txt");
//写入数据
//void write(byte[] b)
//getBytes()将字符串转成数组
fos.write("大数据,yyds".getBytes());
//释放资源
fos.close();
}
}
字节输出流写数据的方式
import java.io.FileOutputStream;
import java.io.IOException;
/*
字节输出流操作步骤:
1、创建字节输出流对象
2、调用write方法写入数据
3、释放资源
void write(byte[] b)
将 b.length个字节从指定的字节数组写入此文件输出流。
void write(byte[] b, int off, int len)
将 len字节从位于偏移量 off的指定字节数组写入此文件输出流。
void write(int b)
将指定的字节写入此文件输出流。
*/
public class FileOutputStreamDemo2 {
public static void main(String[] args) throws IOException {
//创建字节输出流
FileOutputStream fos = new FileOutputStream("a.txt");
//调用write方法写入数据
//void write(int b) 将指定的字节写入此文件输出流。
//存储的是int数据对应的ASCII码值
fos.write(97);//-a
fos.write(98);//-b
fos.write(99);//-c
//void write(byte[] b) 将 b.length个字节从指定的字节数组写入此文件输出流。
byte[] byts = {97,98,99,100,101};
fos.write(byts);
//void write(byte[] b, int index, int length)
//将length字节从位于偏移量index的指定字节数组写入此文件输出流。
fos.write(byts,1,3);
fos.close();
}
}
字节输出流写数据常见问题
import java.io.FileOutputStream;
import java.io.IOException;
/*
1、没有换行,如何实现换行呢?
为什么我们上一个代码没有进行换行呢?
因为我们在写数据的时候,只写入了字节,没有写入换行符
如何实现呢?
理论上写完一部分,再写入一个换行符进行换行
每个系统的换行符都不大一样
Windows: \r\n
Mac: \r
Linux: \n
2、每次运行将历史的数据覆盖了,如何实现追加写入呢?
追加:在原有的文件内容上继续添加一些新的内容
覆盖:将原有的文件内容删掉,再添加一些新的内容
public FileOutputStream(String name, boolean append)
*/
public class FileOutputStreamDemo3 {
public static void main(String[] args) throws IOException {
//创建字节输出流对象(会出现异常)
//FileOutputStream fos = new FileOutputStream("a1.txt");
//追加写入:
//用public FileOutputStream(String name, boolean append)
//输入 文件名,是否追加
FileOutputStream fos = new FileOutputStream("a1.txt", true);
//调用write方法写入数据
for(int i=0;i<10;i++){
fos.write(("大数据,yyds"+i).getBytes());
fos.write("\r\n".getBytes());
}
fos.close();
}
}
字节输入流读取数据
import java.io.FileInputStream;
import java.io.IOException;
/*
FileInputStream: 字节输入流
1、创建字节输入流对象
2、调用read()方法读取数据,输出到控制台
3、释放资源
int read()
从该输入流读取一个字节的数据。
int read(byte[] b)
从该输入流读取最多 b.length个字节的数据为字节数组。
*/
public class FileInputStreamDemo1 {
public static void main(String[] args) throws IOException {
//创建字节输入流对象(会出现异常)
FileInputStream fis = new FileInputStream("a.txt");
//调用read()方法读取数据,输出到控制台
//int read() 从该输入流读取一个字节的数据。
//返回一个int型数据
// System.out.println(fis.read());
//将int型数据强转成字符char类型
// System.out.println((char) fis.read());
// System.out.println((char) fis.read());
// System.out.println((char) fis.read());
//我们发现,当文件的内容过多的时候,一个字节一个字节的去读,发现很麻烦,而且语句重复
//使用循环改进,使用哪种循环呢?
//因为不知道循环多少此,所以我们采用while循环
//要想使用while循环,就得知道跳出循环的条件
//我们想一下,什么时候停止,应该是读到文件末尾的时候停止
//API告诉了我们什么时候读到了文件末尾,如果达到文件的末尾,read()方法返回 -1
int b = 0;
// 如果这样的话,read()方法会在while中读一次
// 输出语句的时候再读一次,所以会跳着输出
// while (fis.read()!=-1){
// System.out.println((char)fis.read());
//所以改为就在while中读一次,并用变量b接收
//将b强转成char类型再输出
while ((b=fis.read())!=-1){
System.out.println((char)b);
}
fis.close();
}
}
import java.io.FileInputStream;
import java.io.IOException;
/*
字节输入流读取数据的第二种方式:一次读取一个字节数组
int read(byte[] b) 从该输入流读取最多 b.length个字节的数据为字节数组。
结果 :读入缓冲区的总字节数,如果没有更多的数据,因为文件的结尾已经到达, -1 。
*/
public class FileInputStreamDemo2 {
public static void main(String[] args) throws IOException {
//创建字节输入流对象
FileInputStream fis = new FileInputStream("a.txt");//a.txt中有11个字母
//int read(byte[] b) 从该输入流读取最多 b.length个字节的数据为字节数组。
// byte[] bytes = new byte[13];
// int read = fis.read(bytes);
// //返回的是该数组实际读取到的字节的长度(个数)
// System.out.println(read);//11
// //遍历数组获取数组里面的内容
// for(byte b : bytes){
// System.out.print((char)b);
// }
//
// System.out.println("=======================");
// //此时我想输出字符串类型--字节数组转字符串
// String s = new String(bytes,0,read);
// System.out.println(s);
//字节流读取第二种方式读取数据的最终代码
byte[] bytes = new byte[1024];//开发中这里数值最好是1024的倍数
int length = 0;
while ((length=fis.read(bytes))!=-1){
String s = new String(bytes, 0, length);
System.out.println(s);
}
//释放资源
fis.close();
}
}
int read(byte[] b)读取方式
字节输入流和字节输出流实现文件复制
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/*
文件复制:
数据源:从哪里读
a.txt -- 读取数据 -- FileInputStream
目的地:写到哪里去
b.txt -- 写出数据 -- FileOutputStream
*/
public class FileCopyDemo1 {
public static void main(String[] args) throws IOException {
//创建字节输入流对象
//编译时期异常,这里就不try...catch...了
//直接抛出
FileInputStream fis = new FileInputStream("a.txt");
//创建字节输出流对象
//编译时期异常,同上
FileOutputStream fos = new FileOutputStream("b.txt");
//一次读写一个字节
int b=0;
//读是一个字节一个字节的读,写也是如此,没有做任何转换,它的内部会做转换
while ((b=fis.read())!=-1){
System.out.println(b);
fos.write(b);
}
//释放资源
//这里有个规范:按照你创建的输入流和输出流对象的顺序
//自下而上的去释放。例如先创建的fis,后创建的fos。
//那么释放顺序就是先fos,再fis。
fos.close();
fis.close();
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/*
将E:\下面的ftm.jpg复制到D:\盘的根目录下
数据源:
E:\ftm.jpg -- 读取数据 -- FileInputStream
目的地:
D:\冯提莫.jpg -- 写出数据 -- FileOutputStream
*/
public class FileCopyDemo2 {
public static void main(String[] args) throws IOException {
//创建字节输入流对象
//编译时期异常,这里就不try...catch...了
//直接抛出
FileInputStream fis = new FileInputStream("E:\\ftm.jpg");
//创建字节输出流对象
//编译时期异常,同上
FileOutputStream fos = new FileOutputStream("D:\\冯提莫.jpg");
int b = 0;
while ((b = fis.read()) != -1) {
fos.write(b);
}
//释放资源
//这里有个规范:按照你创建的输入流和输出流对象的顺序
//自下而上的去释放。例如先创建的fis,后创建的fos。
//那么释放顺序就是先fos,再fis。
fos.close();
fis.close();
}
}
字节缓冲区流
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/*
字节缓冲区流比字节流效率更高,速度更快
缓冲区类(高效类)
字节缓冲输出流:
BufferedOutputStream
构造方法:
BufferedOutputStream(OutputStream out)
创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
字节缓冲输入流:
BufferedInputStream
*/
//----------------字节缓冲输出流----------------
public class BufferedOutputStreamDemo1 {
public static void main(String[] args) throws IOException {
//BufferedOutputStream(OutputStream out)
//创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
//创建一个字节输出流对象-编译时期异常
//FileOutputStream fos = new FileOutputStream("b1.txt");
//将创建好的字节输出流对象传入字节缓冲输出流的有参构造方法中
//BufferedOutputStream bos = new BufferedOutputStream(fos);
//开发中推荐该方式创建(匿名对象)
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b1.txt"));
//往文件中写入数据
//void write(byte[] b)
bos.write("大数据,yyds;朱佳乐真帅!".getBytes());//将字符串转成字节数组
//在没有释放资源的情况下运行程序,执行完毕之后,发现b1.txt中并没有内容,这是为什么呢?
//因为写入的内容都存在了缓冲区中,需要刷新缓冲区将缓冲输出字节写入底层输出流。
//public void flush()
//throws IOException
//刷新缓冲输出流。 这将强制任何缓冲输出字节写入底层输出流。
//flush()方法仅刷新缓冲区,不会关闭IO通道。
//所以bos还能继续用
bos.flush();
//释放资源
//关闭之前也对缓冲区进行了一次刷新
//关闭之后bos不能用了
bos.close();
//在释放资源之后,代码可以写,运行也不会报错
//但是这里的内容就不会添加到b1.txt中了,因为释放资源之后
//已经把通道关闭了,此时bos不能用了
//bos.write("数加科技".getBytes());
//IO通道已经关闭了,此时再刷新缓冲区,就会报错
//IOException: Stream Closed
//bos.flush();
}
}
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
/*
缓冲区类(高效类)
字节缓冲输出流:
BufferedOutputStream
字节缓冲输入流:
BufferedInputStream
构造方法:
BufferedInputStream(InputStream in)
创建一个 BufferedInputStream并保存其参数,输入流 in ,供以后使用。
问题:
我们在使用字节流读取中文的时候,一个一个字节的读取,发现强转之后,出现了我们看不懂的字符
*/
//----------------字节缓冲输入流----------------
public class BufferedInputStreamDemo1 {
public static void main(String[] args) throws IOException {
//BufferedInputStream(InputStream in)
//创建一个 BufferedInputStream并保存其参数,输入流 in ,供以后使用。
//创建BufferedInputStream对象,传参使用匿名对象的形式
BufferedInputStream bif = new BufferedInputStream(new FileInputStream("b1.txt"));
// 一次读取一个字节
//public int read() 结果 数据的下一个字节,如果达到流的末尾, -1
//该方法重写了 FilterInputStream 中的read()方法
int b=0;
while ((b=bif.read())!=-1){
System.out.println((char) b);
}
//我们在使用字节流读取中文的时候,一个一个字节的读取,
//发现强转之后,出现了我们看不懂的字符。
System.out.println("=======================================");
//一次读取一个字节数组
//public int read(byte[] b)
//read返回-1以指示文件结束,则此方法返回-1 。否则,此方法返回实际读取的字节数。
byte[] bytes = new byte[1024];
//假如说,我数组读到第1024个字节的时候,我第1024个字节和第1025个字节两个加在一起
//表示一个汉字的时候。也会出现编码问题(出现我们看不懂的字符)
//所以说读文本文件的时候最好用字符流。
int length = 0;
while ((length = bif.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, length));
}
//在使用字节流读取中文的时候,一个一个字节数组的读取,
//不会出现我们看不懂的字符。
//释放资源
bif.close();
}
}
字符流(转换流)
/*
转换流出现的原因及思想
由于字节流操作中文不是特别方便,所以,java就提供了转换流。
字符流(转换流) = 字节流 + 编码表
加密:把能看懂转成看不懂的(编码)
举例:String -- byte[]
解密:把看不懂的转成能看懂的(解码)
举例:byte[] -- String
编码的格式与解码的格式要一致,否则解码出来的内容你可能看不懂
*/
import java.nio.charset.Charset;
import java.util.Arrays;
public class ZhuanHuanliuDemo {
public static void main(String[] args) throws Exception {
//查看当前的编码格式
//Charset类中有个defaultCharset()方法,查看默认编码
System.out.println(Charset.defaultCharset());
//加密:把能看懂转成看不懂的(编码)
//举例:String -- byte[]
String s = "朱佳乐真帅!";
//byte[] getBytes(Charset charset)
//使用给定的charset将该String编码为字节序列,将结果存储到新的字节数组中。
//此时会出现编译时期异常
//byte[] b1 = s.getBytes("UTF-8");
//观察输出结果发现:UTF-8是3个字节表示一个汉字
//System.out.println(Arrays.toString(b1));
byte[] b1 = s.getBytes("Unicode");
System.out.println(Arrays.toString(b1));
//解密:把看不懂的转成能看懂的(解码)
//byte[] -- String
//String(byte[] bytes, Charset charset)
//构造一个新的String由指定用指定的字节的数组解码charset 。
//原则上用什么编码加密,就用什么编码解密。
//String s1 = new String(b1,"UTF-8");
String s1 = new String(b1,"Unicode");
//观察输出结果发现:Unicode两个字节组成一个中文字符
System.out.println(s1);
}
}
编码表图解
字符输出流
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
/*
Writer:(java提供操作字符流的顶层父类)
由于Writer是一个抽象类,所以我们用它的具体的子类实现它的功能:OutputStreamWriter
OutputStreamWriter 字符输出流(字符转换流)
所得到的字节在写入底层输出流之前累积在缓冲区中。
可以指定此缓冲区的大小,但是默认情况下它大部分用于大多数目的。
构造方法:
OutputStreamWriter(OutputStream out)
创建一个使用默认字符编码的OutputStreamWriter。
OutputStreamWriter(OutputStream out, String charsetName)
创建一个使用命名字符集的OutputStreamWriter。
*/
public class OutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
//创建字符流输出对象
//如果目标文件不存在,会自动创建
//OutputStreamWriter(OutputStream out)
//创建一个使用默认字符编码的OutputStreamWriter。
//OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b2.txt"));
//OutputStreamWriter(OutputStream out, String charsetName)
//创建一个使用命名字符集的OutputStreamWriter。
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream("b3.txt"), "GBK");
//往文件中写入数据
//osw.write("我爱中国");
osw2.write("我爱家乡");
//释放资源
//osw.close();
osw2.close();
}
}
OutputStreamWriter写数据的5个方法
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
/*
OutputStreamWriter写数据的5个方法:
public void write(int c)
public void write(char[] cbuf)
public void write(char[] cbuf,int off,int len)
public void write(String str)
public void write(String str,int off,int len)
*/
public class OutputStreamWriterDemo2 {
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b4.txt"));
//写数据,写在了缓冲区中,需要刷新缓冲区
//public void write(int c)
//一次写一个字节
osw.write(99);
osw.flush();
//public void write(char[] cbuf)
//一次写一个字符数组
char[] chars = {'a','b','c','d','e'};
osw.write(chars);
osw.flush();
//public void write(char[] cbuf,int index,int length)
//一次写入字符数组的一部分
osw.write(chars, 1, 3);
osw.flush();
//public void write(String str)
//一次写入一个字符串
osw.write("刘生发真帅!");
osw.flush();
//public void write(String str,int off,int len)
//一次写入字符串的一部分
//字符串是由一个一个字符组成的,底层实现还是一个字符数组
//也有下标和索引
osw.write("刘生发真帅!",0,3);
osw.flush();
//释放资源
osw.close();
}
}
字符输入流
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/*
Reader: 字符流的顶层父类
Reader是抽象类,不能实例化。所以需要它的一个具体的子类来实现它的功能:InputStreamReader
InputStreamReader: 字符输入流
构造方法:
InputStreamReader(InputStream in)
创建一个使用默认字符集的InputStreamReader。
InputStreamReader(InputStream in, String charsetName)
创建一个使用命名字符集的InputStreamReader。
*/
public class InputStreamReaderDemo1 {
public static void main(String[] args) throws IOException {
//创建字符输入流
//InputStreamReader isr = new InputStreamReader(new FileInputStream("b4.txt"));
InputStreamReader isr = new InputStreamReader(new FileInputStream("b4.txt"),"UTF-8");
//读取数据
//int read()
//一次读一个字符
//System.out.println((char) isr.read());
int b =0;
while ((b=isr.read())!=-1){
System.out.print((char)b);
}
//释放资源
isr.close();
}
}
InputStreamReader读取数据的方法
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/*
InputStreamReader读取数据的方法:
public int read():一次读取一个字符
public int read(char[] cbuf):一次读取一个字符数组
*/
public class InputStreamReaderDemo2 {
public static void main(String[] args) throws IOException {
//创建字符输入流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream("b4.txt"));
//读取数据
//public int read():一次读取一个字符
// int c = 0;
// while ((c = isr.read()) != -1) {
// System.out.println((char) c);
// }
//public int read(char[] cbuf):一次读取一个字符数组
char[] chars = new char[1024];
int length = 0;
while ((length = isr.read(chars)) != -1) {
System.out.println(length);
System.out.println(new String(chars, 0, length));
}
//释放资源
isr.close();
}
}
字符流复制文本文件
import java.io.*;
/*
把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中
数据源:
a.txt -- 读取数据 -- 字符输入流(字符转换流) -- InputStreamReader
目的地:
b.txt -- 写出数据 -- 字符输出流(字符转换流) -- OutputStreamWriter
*/
public class FileCopyDemo3 {
public static void main(String[] args) throws IOException {
//创建字符输入流对象
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));
//创建字符输出流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"));
//读写数据
// //一次读写一个字符
// int c = 0;
// while ((c = isr.read()) != -1) {
// osw.write(c);
// osw.flush();
// }
//一次读写一个字符数组
char[] chars = new char[1024];
int length = 0;
while ((length = isr.read(chars)) != -1) {
osw.write(chars, 0, length);
osw.flush();
}
//释放资源
osw.close();
isr.close();
}
}
字符流(转换流)的简化写法
import java.io.*;
/*
由于我们正常做字符流的处理的时候,一般都不会去刻意传入编码,用的都是默认的编码
基本数不会去指定。
而通过学习完转换流之后,发现,名字有点长,所以Java就提供了子类给我们使用
字符流 = 字节流 + 编码表
OutputStreamWriter = FileOutputStream + 编码表(Unicode)
InputStreamReader = FileInputStream + 编码表(Unicode)
字符转换流的简化写法:
字符输出流:
FileWriter
字符输入流:
FileReader
需求:复制文件
*/
public class FileCopyDemo5 {
public static void main(String[] args) throws IOException {
//创建字符输入流对象
// InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));
//创建简化后的字符输入流对象
FileReader fr = new FileReader("a.txt");
//创建简化后的字符输出流对象
FileWriter fw = new FileWriter("c1.txt");
//第一种方式:一次读写一个字符
// int c = 0;
// while ((c=fr.read())!=-1){
// fw.write(c);
// fw.flush();
// }
//第二种方式:一次读写一个字符数组
char[] chars = new char[1024];
int length = 0;
while ((length=fr.read(chars))!=-1){
fw.write(chars, 0, length);
fw.flush();
}
//释放资源
fw.close();
fr.close();
}
}
字符缓冲流
import java.io.*;
/*
字符流为了高效读写,也提供了相对应的字符缓冲流
BufferedWriter:字符缓冲输出流
BufferedReader:字符缓冲输入流
BufferedWriter:字符缓冲输出流、
将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入。
可以指定缓冲区大小,或者可以接受默认大小。 默认值足够大,可用于大多数用途
*/
public class BufferedWriterDemo1 {
public static void main(String[] args) throws IOException {
//-------------BufferedWriter:字符缓冲输出流-----------------
//创建字符缓冲输出流
//构造方法:
//BufferedWriter(Writer out)
//创建使用默认大小的输出缓冲区的缓冲字符输出流。
// BufferedWriter bw = new BufferedWriter(
// new OutputStreamWriter(
// new FileOutputStream("b5.txt")));
//简化写法
BufferedWriter bw = new BufferedWriter(new FileWriter("b5.txt"));
//写数据
bw.write("hello");
bw.write("\r\n");
bw.write("world");
bw.write("\r\n");
bw.write("java");
bw.write("\r\n");
bw.write("hadoop");
bw.flush();
//释放资源
bw.close();
}
}
import java.io.*;
/*
BufferedReader:字符缓冲输入流
BufferedReader(Reader in)
创建使用默认大小的输入缓冲区的缓冲字符输入流。
*/
public class BufferedReaderDemo1 {
public static void main(String[] args) throws IOException {
//---------------BufferedReader:字符缓冲输入流-------------------
//创建字符缓冲输入流对象
// BufferedReader br = new BufferedReader(
// new InputStreamReader(
// new FileInputStream("a.txt")));
//简化写法
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
//第一种:一次只读一个字符
// int c = 0;
// while ((c = br.read()) != -1) {
// System.out.print((char) c);
// }
//第二种:一次读取一个字符数组
char[] chars = new char[1024];
int length = 0;
while ((length=br.read(chars))!=-1){
System.out.println(new String(chars,0,length));
}
//释放资源
br.close();
}
}
字符缓冲流复制文本文件及System类中返回当前时间的方法
import java.io.*;
/*
使用高效字符流复制文件
*/
public class FileCopyDemo7 {
public static void main(String[] args) throws IOException {
//创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("b.txt"));
//创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("ceshi2.txt"));
//System类包含几个有用的类字段和方法。 它不能被实例化。工具类:构造方法私有化
//public static long currentTimeMillis() 返回当前时间(以毫秒为单位)。
long start = System.currentTimeMillis();
//一次读取一个字符数组
char[] chars = new char[1024];
int length = 0;
while ((length = br.read(chars)) != -1) {
bw.write(chars, 0, length);
bw.flush();
}
long end = System.currentTimeMillis();
System.out.println("总耗费时间:" + (end - start));
//释放资源
bw.close();
br.close();
}
}
字符缓冲流的特殊方法
import java.io.*;
/*
字符缓冲流的特殊方法:
BufferedWriter:
public void newLine()--万能换行符
throws IOException 写一行行分隔符。
行分隔符字符串由系统属性line.separator定义,
并不一定是单个换行符('\ n')字符。
BufferedReader:
public String readLine()--一次读取一行
throws IOException读一行文字。
一行被视为由换行符('\ n'),回车符('\ r')中的任何一个或随后的换行符终止。
如果已达到流的末尾,则为null
*/
public class BufferedWriterDemo2 {
public static void main(String[] args) {
//write();
read();
}
//-------------字符缓冲输入流-----------------
public static void read(){
//创建字符缓冲输入流
//有编译时期异常,这里直接try..catch..
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("b6.txt"));
// String s = br.readLine();
// System.out.println(s);
//
// String s1 = br.readLine();
// System.out.println(s1);
//
// String s2 = br.readLine();
// System.out.println(s2);
//用循环改进读取数据,因为我们不知道一个文件到底有多少行,我们用while循环
//如果已达到流的末尾,则为null
String line = null;
while ((line=br.readLine())!=null){
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//-------------字符缓冲输出流----------------
public static void write() {
//创建字符缓冲输出流
//有编译时期异常,这里直接try..catch..
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter("b6.txt"));
//往文件中写入数据
for (int i = 0; i < 10; i++) {
bw.write("大数据" + i);
//\r\n:Windows中的换行符
//bw.write("\r\n");
bw.newLine();
bw.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//在finally中释放资源
//编译时期异常,直接try..catch..
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字符缓冲流特殊功能复制文件
import java.io.*;
/*
字符缓冲流特殊功能复制文件:
数据源:
a.txt -- 读取数据 -- 字符输入流 -- InputStreamReader -- FileReader -- BufferedReader
目的地:
b7.txt -- 写出数据 -- 字符输出流 -- OutputStreamWriter -- FileWriter -- BufferedWriter
*/
public class FileCopyDemo8 {
public static void main(String[] args) throws IOException {
//创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
//创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("b7.txt"));
String line = null;
while ((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//释放资源
bw.close();
br.close();
}
}
序列化流
import java.io.Serializable;
/*
未序列化异常:
java.io.NotSerializableException: com.shujia.wyh.day29.Person
只有支持java.io.Serializable接口的对象才能写入流中
类的序列化实现是由java.io.Serializable接口的类启用的
不实现此接口的类的对象不会使任何状态的序列化或者反序列化
可序列化的类的所有子类都是可以被序列化的
通过观察API发现,Serializable接口中没有任何方法和常量,说明它是一个标记接口
(回想以下我们之前说Object类中的克隆方法)
报错解析:
java.io.InvalidClassException(无效的类异常): com.shujia.wyh.day29.Person;
local class incompatible(本地类不兼容):
stream classdesc serialVersionUID = 5698437318079510433,
local class serialVersionUID = 304687058414395716
为什么会出现这样的问题呢?
根据我们简单的分析后发现,Person类实现了Serializable标记接口
它本身应该有一个标记值,假设一开始的标记值是id=100
在没有修改Person类之前:
Person.class -- id=100
写数据的时候:object -- id=100
读数据的时候:object -- id=100
进行修改之后:(把private int age;中的private删了)
Person.class -- id=200
写数据的时候:object -- id=100
读数据的时候:object -- id=100
在实际开发中,我们因为业务问题,不允许重复往文件或者某数据库中重复存储(写入),
那怎么解决呢?
这个问题实际上是由于id值的不匹配导致的(class文件的id值与存储对象的id值不匹配)
如果说有一个办法可以让这个ID值固定不变就好了。
Java在序列化中提供给了一个ID值(serialVersionUID),可以让我们去设定
我们不需要手动设置,自动生成即可。将鼠标放在类名上,按下alt+enter键自动生成
IDEA需要做一些其他的设置File-->Settings-->Editor-->Inspections-->UID
需求:
现在我不想在序列化的时候,把年龄也序列化了
Java提供了一个关键字,可以让我们在序列化的时候选择哪些成员可以不被序列化
叫做:transient
*/
public class Person implements Serializable {//⬅只有支持Serializable接口的对象才能写入流中
//自动生成的ID值
private static final long serialVersionUID = -6941805929936535429L;
private String name;
//当我调用write()方法写完数据之后
//我把private int age;改成int age;
//再把write()方法注释掉,用read()方法去读
//之前写好的数据
//private int age;
//int age;
//此时就会报错:InvalidClassException(无效的类异常)
//local class incompatible(本地类不兼容)
private transient int age;//使用transient关键字让成员变量age不被序列化
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import java.io.*;
/*
序列化(持久化):把对象按照流一样的方式存到文本文件或者数据库或者网络中传输等
对象 -- 流数据:ObjectOutputStream(继承自OutputStream)
构造方法:
ObjectOutputStream(OutputStream out)
创建一个写入指定的OutputStream的ObjectOutputStream。
成员方法:
void writeObject(Object obj)
将指定的对象写入ObjectOutputStream。
反序列化:把文本文件中的对象数据或者网络中的流数据给还原成一个对象。
流数据 -- 对象:ObjectInputStream(继承自InputStream)
构造方法:
ObjectInputStream(InputStream in)
创建从指定的InputStream读取的ObjectInputStream。
成员方法:
Object readObject()
从ObjectInputStream读取一个对象。
*/
public class ObjectStreamDemo {
public static void main(String[] args) {
//写方法:将对象存到文件中,这个过程其实就是将对象进行序列化(持久化)
// try {
// write();
// } catch (Exception e) {
// e.printStackTrace();
// }
//读方法:把文本文件中的对象数据或者网络中的流数据给还原成一个对象
try {
read();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void read() throws Exception {
//ObjectInputStream(InputStream in)
//创建从指定的InputStream读取的ObjectInputStream。
//此时产生编译时期异常
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
//Object readObject()
//从ObjectInputStream读取一个对象。
Object o = ois.readObject();
//为什么可以直接输出对象成员信息呢?
//因为此时readObject()方法返回的其实是Person类的
//对象,然后用Object接收---多态
System.out.println(o);
//向下转型
Person p = (Person)o;
System.out.println(p);
//释放资源
ois.close();
}
public static void write() throws Exception {
//ObjectOutputStream(OutputStream out)
//创建一个写入指定的OutputStream的ObjectOutputStream。
//此时产生编译时期异常
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
//创建一个对象
Person lele = new Person("朱佳乐", 20);
//将对象写入文件
//void writeObject(Object obj)
//将指定的对象写入ObjectOutputStream。
oos.writeObject(lele);
//释放资源
oos.close();
}
}
IO流练习
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
/*
把ArrayList集合中的字符串数据存储到文本文件
*/
public class IOTest1 {
public static void main(String[] args) throws IOException {
//创建集合对象
ArrayList<String> list = new ArrayList<>();
//向集合中添加元素
list.add("hello");
list.add("world");
list.add("java");
list.add("bigdata");
//创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("练习1.txt"));
//遍历集合
for (String s : list) {
bw.write(s);
bw.newLine();
}
//刷新缓冲区
bw.flush();
//释放资源
bw.close();
}
}
/*
键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低存入文本文件
*/
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;
public class IOTest2 {
public static void main(String[] args) throws IOException {
//创建Scanner对象,System.in是字节流
Scanner sc = new Scanner(System.in);
//创建集合存储学生对象
//由于按照总分从高到低存入,需要自定义排序,优先选择TreeSet
TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//按照总分从高到低
int i = o2.getSum() - o1.getSum();
//总分一样,语文成绩不一定一样
int i2 = i == 0 ? o1.getChinese() - o2.getChinese() : i;
//总分一样,语文成绩一样,数学成绩不一定一样
int i3 = i2 == 0 ? o1.getMath() - o2.getMath() : i2;
//各科成绩都一样,名字不一定一样
int i4 = i3 == 0 ? o1.getName().compareTo(o2.getName()) : i3;
return i4;
}
});
System.out.println("==================开始录入学生信息==================");
for (int i = 1; i <= 5; i++) {
System.out.println("请输入第" + i + "个学生的信息:");
System.out.println("姓名:");
String name = sc.next();
System.out.println("语文成绩:");
int chinese = sc.nextInt();
System.out.println("数学成绩:");
int math = sc.nextInt();
System.out.println("英语成绩:");
int english = sc.nextInt();
//创建学生对象
Student s = new Student(name, chinese, math, english);
//将学生对象添加到集合中
treeSet.add(s);
}
//创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("练习2.txt"));
//遍历集合,将学生信息写入到文件中
bw.write("==================学生信息如下==================");
bw.newLine();
bw.write("姓名\t语文成绩\t数学成绩\t英语成绩\t总分");
bw.newLine();
bw.flush();
for(Student s : treeSet){
String name = s.getName();
int chinese = s.getChinese();
int math = s.getMath();
int english = s.getEnglish();
int sum = s.getSum();
bw.write(name+"\t"+chinese+"\t"+math+"\t"+english+"\t"+sum+"\t");
bw.newLine();
bw.flush();
}
//释放资源
bw.close();
System.out.println("学生信息存储完毕!");
}
}
import java.io.*;
import java.util.Arrays;
/*
已知s.txt文件中有这样的一个字符串:“hcexfgijkamdnoqrzstuvwybpl”
请编写程序读取数据内容,把数据排序后写入ss.txt中。
*/
public class IOTest3 {
public static void main(String[] args) throws IOException {
//创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("src/com/shujia/wyh/day28/s.txt"));
String s = br.readLine();
//释放资源
br.close();
//将字符串转成字符数组
char[] chars = s.toCharArray();
//使用Arrays工具类中的sort方法
Arrays.sort(chars);
//创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("src/com/shujia/wyh/day28/ss.txt"));
bw.write(chars,0,chars.length);
bw.flush();
bw.close();
}
}
IO流总结
/*
IO流总结:就是对数据存储和取出做操作
I:input 输入流
O:output 输出流
分类:
输入流
A: 字节输入流(InputStream -- FileInputStream)
FileInputStream fis = new FileInputStream("");
读取数据的两种方式:
1、一次读取一个字节
int b = 0;
while((b=fis.read())!=-1){
System.out.println((char)b);
}
2、一次读取一个字节数组
byte[] bytes = new byte[1024];
int length = 0;
while((length=fis.read(bytes))!=-1){
System.out.println(new String(bytes,0,length));
}
字节缓冲输入流(BufferedInputStream)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(""));
1、一次读取一个字节
int b = 0;
while((b=bis.read())!=-1){
System.out.println((char)b);
}
2、一次读取一个字节数组
byte[] bytes = new byte[1024];
int length = 0;
while((length=bis.read(bytes))!=-1){
System.out.println(new String(bytes,0,length));
}
字符流 = 字节流+编码表
B:字符输入流(Reader -- InputStreamReader)
InputStreamReader isr = new InputStreamReader(new FileInputStream(""));
简化格式:FileReader
FileReader fr = new FileReader("");
1、一次读取一个字符
int c = 0;
while((c=fr.read())!=-1){
System.out.println((char)c);
}
2、一次读取一个字符数组
char[] chars = new char[1024];
int length = 0;
while((length=fr.read(chars))!=-1){
System.out.println(new String(chars,0,length));
}
字符缓冲输入流(BufferedReader)
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("")))
简化格式:
BufferedReader br = new BufferedReader(new FileReader(""));
1、一次读取一个字符
int c = 0;
while((c=br.read())!=-1){
System.out.println((char)c);
}
2、一次读取一个字符数组
char[] chars = new char[1024];
int length = 0;
while((length=br.read(chars))!=-1){
System.out.println(new String(chars,0,length));
}
3、使用字符缓冲输入流的特殊方法
String line = null;
while((line=br.readLine())!=null){
System.out.println(line);
}
输出流
A:字节输出流(OutputStream -- FileOutputStream)
FileOutputStream fos = new FileOutputStream("");
1、一次写一个字节
fos.write(97);
2、一次写一个字节数组
fos.write("大数据,yyds".getBytes());
字节缓冲输出流(BufferedOutputStream)
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(""))
1、一次写一个字节
bos.write(97);
2、一次写一个字节数组
bos.write("大数据,yyds".getBytes());
B:字符输出流(Writer -- OutputStreamWriter)
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(""));
简化格式:FileWriter
FileWriter fw = new FileWriter("");
1、一次写一个字符
fw.write(98);
2、一次写一个字符数组
fw.write("数加科技真好".toCharArray());
字符缓冲输出流(BufferedWriter)
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(""));
简化写法:
BufferedWriter bw = new BufferedWriter(new FileWriter(""))
1、一次写一个字符
bw.write(98);
2、一次写一个字符数组
bw.write("数加科技真好".toCharArray());
3、使用字符缓冲输出流对象的特殊方法实现换行
bw.write("");
bw.newLine();
*/