一、Java流式输入输出原理
Java对于输入输出是以流(Stream)的方式进行的,JDK提供各种各样的“流”类,以获取不同类型的数据。
可以理解为将管道插入到文件中,然后从管道获取数据。这个管道外边还可以套管道,外边的管道对数据进行处理,即套了“处理流”。
二、输入输出流分类
按功能:数据流、处理流
按方向:输入流、输出流
按数据单位:字节流、字符流(2个字节)
Java.io内的流类型继承自一下四种:
2种输入输出 * 2中数据单位:(字节) InputStream、OutputStream、(字符)Reader、Writer
Tip:这里的输入输出是站在程序角度来看的
三、字节流和处理流
字节流:从节点读写数据(如文件、内存)
处理流:套在字节流外,对数据进行处理,为程序提供更强大的读写能力
3.1 字节流类型
类型 | 字节流(1字节)InputStream OutputStream | 字符流(2字节) Reader Writer |
File (File) | FileInputStream FileOutputStream | FileReader FileWriter |
MemoryArray (ByteArray/CharArray) | ByteArrayInputStream ByteArrayOutputStream | CharArrayReader CharArrayWriter |
MemoryString (String) | - - | StringReader StringWriter |
Pipe (Piped) | PipedInputStream PipedOutputStream | PipedReader PipedWriter |
3.2 处理流类型
处理类型 | 字节 InputStream/Steam OutputStream | 字符 Reader Writer |
Buffering | BufferedInputStream BufferedOutputStream | BufferedReader BufferedWriter |
Filtering | FilterInputStream FilterOutputStream | FilterReader FilterWriter |
bytes和chaacter之间转换 | InputStreamReader OutputStreamWriter | |
Object Serialization | ObjectInputStream ObjectOutputStream | |
Data conversion | DataInputStream DataOutputStream | |
Counting | LineNumberInputStream | LineNumberReader |
Peeking ahead | PushbackInputStream | PushbackReader |
Printing | PrintStream | PrintWriter |
四、字节流
InputStream
以字节形式向程序输入数据(8bit)
基本步骤:
- 新建FileInputStream对象in
- 打开文件
- try:new一个文件路径的对象,给in;
- catch:FileNotFoundException
- 读取文件
- try:
- 判断in.read()是不是-1, 是的话就到头了,就不读了、
- 关闭in
- catch:IOException
总结:
以字节的形式挨个读取,输出时要用(char)将ASC码转换出来
FileInputStream对象,new、赋值、.read()、close()
两个异常:FileNotFoundException、IOException
public static void main(String[] args) {
int b = 0;
// 新建一个FileInputStream对象
FileInputStream in = null;
try {
// 给FileInputStream赋值
in = new FileInputStream("D:\\工作\\编程\\after 2022.11\\KuangShengShuo\\src\\com\\baidu\\File\\number.txt");
}catch (FileNotFoundException e){
System.out.println("系统找不到指定文件");
System.exit(-1);// 系统非正常退出
}
// 开始读取
long num = 0; // 记录读取了多少个数字
try {
while ((b = in.read() )!= -1){ // 主要是in.read()
System.out.println((char)b);
num++;
}
in.close(); // 关闭输入流
System.out.println();
System.out.println("总共读了" + num + "个字节");
}catch(IOException e){
System.out.println("文件读取错误");
}
}
OutputStream
- 新建:new一个OutputStream对象,=null
- 读写:
- 文件名对应一个对象,赋值给上面新建的对象,这里存在找不到文件的可能(FileNotFoundException)
- 将东西写到对应的OutputStream中,存在复制失败的可能(IOException)
- 关闭:各种close(), (也要IOException)
public static void main(String[] args) {
FileInputStream in = null;
FileOutputStream out = null;
try {
// 新建, 以下需catch FileNotFoundException
in = new FileInputStream("D:\\工作\\编程\\after 2022.11\\KuangShengShuo\\src\\com\\baidu\\File\\number.txt");
out = new FileOutputStream("D:\\工作\\编程\\after 2022.11\\KuangShengShuo\\src\\com\\baidu\\File\\number2.txt");
// 读写。 以下需catch IOException
int b = 0;
while ((b = in.read()) != -1){
out.write((char)b);
}
// 关闭
in.close();
out.close();
}catch(FileNotFoundException e){
System.out.println("系统没有找到指定文件");
System.exit(-1);
}catch (IOException e){
System.out.println("读写错误");
}
Reader/Writer
注意这里的writer,要写成String.valueOf(i)
因为,int是4个字节,API里写入了低16位的2个字节,忽略了高16位的2个字节。
所以,在输入到文件时不妨吧整形转为char 或者字符串
fw.write(String.valueOf(12));
fw.write(Character.valueOf('1'));
public static void main(String[] args) {
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("D:\\工作\\编程\\after 2022.11\\KuangShengShuo\\src\\com\\baidu\\File\\number.txt");
fw = new FileWriter("D:\\工作\\编程\\after 2022.11\\KuangShengShuo\\src\\com\\baidu\\File\\number3.txt");
// 读写
for(int i = 0; i < 30; i++){
fw.write(String.valueOf(i));
}
// 关闭
fr.close();
fw.close();
}catch (FileNotFoundException e){
System.out.println("找不到指定文件");
}catch (IOException e){
System.out.println("文件复制错误");
}
}
五、处理流
5.1 Buffer缓冲流
缓冲是内存中的一块区域,数据在内存中缓冲,然后Flush()立刻写出,需要在close()将缓冲区内容强行输出,否则可能没有输出去。
如果没有buffer,是读一个写一个,很慢;如果有缓冲区,先放内存里,读完后统一写出去,底层会快很多。
BufferedInputStream
构造函数 BufferedInputStream( InputStream
不明白这个mark()和reset()是干啥的。。。
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\工作\\编程\\after 2022.11\\KuangShengShuo\\src\\com\\baidu\\File\\number.txt");
BufferedInputStream in = new BufferedInputStream(fis);
// mark一下
in.mark(2);
// 输出do re mi f
int c = 0;
for (int i = 0; i < 10 && (c = in.read() )!= -1; i++){
System.out.println((char)c);
}
// reset 输出do re mi f
in.reset();
for (int i = 0; i < 10 && (c = in.read() )!= -1; i++){
System.out.println((char)c);
}
// 关闭
in.close();
fis.close();
}catch (FileNotFoundException e){
System.out.println("未找到指定文件");
}catch (IOException e){
System.out.println("读写错误");
}
}
BufferedReader/ BuffreedWriter
bw.write() 配合 bw.newLine() 向文件里写,最后写操作要进行.flush(),才能写进去,不然在缓存里
br.readLine() 读取整行
bw = new BufferedWriter(new FileWriter("文件路径")) 真的像是包在字符流外边的管道
br = new BufferedReader(new FileReader("文件路径"))
最后要.close()
以上,要配合IOException()的catch操作
public static void main(String[] args) {
BufferedWriter bw = null;
BufferedReader br = null;
try {
bw = new BufferedWriter(new FileWriter("D:\\工作\\编程\\after 2022.11\\KuangShengShuo\\src\\com\\baidu\\File\\numBufferWriter.txt"));
String s = null;
for(int i = 0; i < 10; i++){
s = String.valueOf(Math.random());
bw.write(s);
bw.newLine();
}
// 重要!!如果不flush,是写不到文件里的
bw.flush();
br = new BufferedReader(new FileReader("D:\\工作\\编程\\after 2022.11\\KuangShengShuo\\src\\com\\baidu\\File\\numBufferWriter.txt"));
while ((s = br.readLine()) != null){ // 这里是null来判断
System.out.println(s);
}
// 关闭两个处理流
bw.close();
br.close();
}catch (IOException e){
System.out.println("系统错误");
}
}
5.2 转换流
InputStreamReader 和 OutputStreamWriter
如果我们用FileOutputStream流往文件里写东西,是一个字节一个字节的写;外面套上OutputStreamWriter,就是一个字符一个字符的写了。
新建:
OutputStreamWriter osw = new OutputStreamWriter(new一个FileOutputStream对象, "编码格式")
在FileOutputStream中,可以选择是否true, 如果true就不会覆盖原来的,直接接着写
osw.write(内容)
osw.close()
public static void main(String[] args) {
try {
// 新建
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\工作\\编程\\after 2022.11\\KuangShengShuo\\src\\com\\baidu\\File\\numTransfrom1.txt"));
// 写入 .write()
osw.write("hello transform");
//------编码方式 UTF8
System.out.println(osw.getEncoding());
// 关闭 .close()
osw.close();
// 指定编码 new OutputStreamWriter(new FileoutputStream("文件路劲", true),编码格式)
// 加了true,就在原有的文件下面接着写,否则就覆盖了
// 就用上面的osw就行了
osw = new OutputStreamWriter(new FileOutputStream("D:\\工作\\编程\\after 2022.11\\KuangShengShuo\\src\\com\\baidu\\File\\numTransfrom2.txt",true),"ISO8859_1");
osw.write("hello world again!");
System.out.println(osw.getEncoding());
osw.close();
}catch (IOException e){
System.out.println("系统错误");
}
}
5.3 数据流
存取与机器无关的java原始类型数据( int double 等)
DataIutputStream(IutputStream out) // 套在IutputStream外
DataOutputStream(OutputStream out) // 套在OutputStream外
/*
数据流
DataOutputStream( OutputStream out)
注:这里的ByteArrayOutputStream是一种种MemoryArray的字节流,对应字符流是CharArayOutputStream
*/
try {
// 新建
ByteArrayOutputStream baos= new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
// 传输
dos.writeDouble(Math.random());
dos.writeBoolean(true);
// 新建 ByteArrayInputStream 是从 ByteArrayOutputStream对象转换来的,.toByteArray()
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); // 9?
DataInputStream dis= new DataInputStream(bais);
// 传输
System.out.println(dis.readDouble()); // 0.4996368724821276
System.out.println(dis.readBoolean()); // true
// 关闭
dos.close();
baos.close();
dis.close();
bais.close();
}catch (Exception e){
System.out.println("系统错误");
}
}
5.4 打印流、对象流等
略