Java IO

文章目录

  • 基本介绍
    • 流的概念
    • 输入/输出流的分类
      • 节点流和处理流
      • InputStream类
      • OutputStream类
      • Reader类
      • Writer
  • 节点流
    • 节点流类型
    • 节点流的实际应用
  • 处理流
    • 处理流的类型
    • 缓冲流
    • 转换流
    • 数据流
    • Print流
    • Object流
  • 总结

基本介绍

流的概念

在Java程序中,对于数据的输入/输出操作以“流”(stream)方式进行。流只能单方向流动,输入流用来读取数据,输出流用来写出。
Java IO_第1张图片

输入/输出流的分类

  • 按照数据流的方向不同可以分为输入流和输出流;
  • 按照处理数据单位不同可以分为字节流和字符流
  • 按照功能不同可以分为节点流和处理流

节点流和处理流

节点流可以从一个特定的节点读写数据。
处理流是“连接”在已存在的流之上,通过对数据的处理为程序提供更为强大的读写功能。
Java IO_第2张图片

InputStream类

用于向程序输入数据,数据单位为字节。
InputStream相关子类
Java IO_第3张图片
注:上图深色为节点流,浅色为处理流。
InputStream基本方法

abstract int read() 
从输入流读取数据的下一个字节。  
int read(byte[] b) 
从输入流读取一些字节数,并将它们存储到缓冲区 b 。  
int read(byte[] b, int off, int len) 
从输入流读取最多 len字节的数据到一个字节数组。  
void close() 
关闭此输入流并释放与流相关联的任何系统资源。  
long skip(long n) 
跳过并丢弃来自此输入流的 n字节数据。 

OutputStream类

用于向程序输出数据,数据单位为字节。
OutStream相关子类
Java IO_第4张图片
OutStream基本方法

void close() 
关闭此输出流并释放与此流相关联的任何系统资源。  
void flush() 
刷新此输出流并强制任何缓冲的输出字节被写出。  
void write(byte[] b) 
将 b.length字节从指定的字节数组写入此输出流。  
void write(byte[] b, int off, int len) 
从指定的字节数组写入 len个字节,从偏移 off开始输出到此输出流。  
abstract void write(int b)  

Reader类

用于向程序输入数据,数据单位为字符(16 bit)。
Reader相关子类
Java IO_第5张图片

Reader基本方法

int read() 
读一个字符  
int read(char[] cbuf) 
将字符读入数组。  
abstract int read(char[] cbuf, int off, int len) 
将字符读入数组的一部分。  
int read(CharBuffer target) 
尝试将字符读入指定的字符缓冲区。  
long skip(long n) 
跳过字符  
abstract void close() 
关闭流并释放与之相关联的任何系统资源 

Writer

用于向程序输出数据,数据单位为字符。
Writer相关子类
Java IO_第6张图片
Writer基本方法

abstract void close() 
关闭流,先刷新。  
abstract void flush() 
刷新流。  
void write(char[] cbuf) 
写入一个字符数组。  
abstract void write(char[] cbuf, int off, int len) 
写入字符数组的一部分。  
void write(int c) 
写一个字符  
void write(String str) 
写一个字符串  
void write(String str, int off, int len) 
写一个字符串的一部分。 

以上关于基本方法的介绍部分摘自JDK API文档

节点流

通俗地讲,节点流就像一根管子,程序就像一个水桶,管子直接插入水桶并通过管子进行数据的输入/输出。

节点流类型

Java IO_第7张图片

节点流的实际应用

下面给出FileInputStream,FileOutputStream,FileReader,FileWriter的小例子。
InputStream

import java.io.*;
public class TestFileInputStream {
    public static void main(String args[]){
        int b = 0;
        FileInputStream in = null;
        try{
            in = new FileInputStream("C:\\Users\\86198\\IdeaProjects\\zhoulr\\src\\com\\company\\TestFileInputStream.java");
            //此处文件路径根据你要读取的文件进行书写
        }catch(FileNotFoundException e){
            System.out.println("找不到指定文件");
            System.exit(-1);//结束程序
        }
        try {
            long num = 0;
            while ((b = in.read()) != -1)//检测是否输到文件尾
            {
                System.out.print((char)b);
                num++;
            }
            in.close();
            System.out.println();
            System.out.println("共读取了"+num+"个字节");
        }catch(IOException e1){
            System.out.println("文件读取错误");System.exit(-1);
        }
    }
}

结果
我只截取了后面的一部分,其实就是把这个代码打印出来了(因为我的文件路径就是这个代码的路径)。其中出现乱码的原因是InputStream是字节流,单位是一个字节,但中文需要两个字节所以会出现乱码。
Java IO_第8张图片
OutputStream

import java.io.*;
public class TestOutputStream {
    public static void main(String args[]){
        int b = 0;
        FileInputStream in = null;
        FileOutputStream out = null;
        try{
            in = new FileInputStream("D:/HelloWorld.java");
            //写需要复制的文件路径
            out = new FileOutputStream("D:/JAVA/test.txt");
			//写被复制的文件路径
            while((b=in.read())!=-1)
                out.write(b);
            in.close();//关闭输入流
            out.close();//关闭输出流
        }catch(FileNotFoundException e1){
            System.out.println("找不到指定文件");
            System.exit(-1);
        }catch(IOException e2){
            System.out.println("文件复制错误");
            System.exit(-1);
        }
        System.out.println("文件已成功复制");
    }
}

结果
这个就只有一句文件成功复制…当然如果路径不正确的话应该会显示错误。然后在文件里就可以查看相关信息了。

FileReader

import java.io.*;
public class TestFileReader {
    public static void main(String args[]) {
        FileReader fr = null;
        int a = 0;
        try {
            fr = new FileReader("C:\\Users\\86198\\IdeaProjects\\zhoulr\\src\\com\\company\\TestFileReader.java");
            int l = 0;
            while ((a = fr.read()) != -1) {
                System.out.print((char) a);
            }
            fr.close();
        } catch (FileNotFoundException e1) {
            System.out.println("找不到指定文件");
        } catch (IOException e2) {
            System.out.println("文件读取错误");
        }
    }
}

结果
其实这个程序跟上一个InputStream是有很多相似之处的,但它的结果不会出现乱码,因为Reader本身是字符流,单位是字符,可以输出中文。
Java IO_第9张图片
FileWriter

import java.io.*;
public class TestFileWriter {
    public static void main(String args[]){
        FileWriter fw = null;
        try{
            fw = new FileWriter("D:\\JAVA\\test.txt");
            for(int i=0;i<=50000;i++){
                fw.write(i);
            }
            fw.close();
        }catch(IOException e){
            e.printStackTrace();
            System.out.println("文件写入错误");
            System.exit(-1);
        }
    }
}

结果
这个程序和OutputStream那个其实还是有很大区别的,这个程序利用Writer也是字符输出的形式,将0~50000的字符都读入了文件中(最大应该是65535个字符),Java采用的是Unicode码,65535个可以包含差不多所有国家的文字了。接下来看一下这个文件里的内容。有一些是乱码,应该是因为在我的电脑上不支持查看…但条件允许的话应该都是可以显示的。
Java IO_第10张图片

处理流

处理流相当于是另一根管道包在节点流或处理流的外面(人生无常大肠包小肠hhhh),通过处理流能让数据的处理更简洁高效,为程序提供更强大的读写功能。

处理流的类型

Java IO_第11张图片

缓冲流

缓冲流套接在相应节点流上,对输入输出的数据提供缓冲的功能,提高了读写的效率,同时增加了一些新方法。
缓冲流相关构造方法

1.BufferdReader(Reader in)
2.BufferedReader(Reader in,int sz)//sz为自定义缓存区大小
3.BufferedWriter(Writer out)
4.BufferedWriter(Writer out,int sz)
5.BufferedInputStream(InputStream in)
6.BufferedInputStream(InputStream in,int sz)
7.BufferedWriter(OutputStream out)
8.BufferedWriter(OutputStream out,int sz)

注意事项

  • 缓冲流支持mark和reset方法。
  • BufferedReader提供了readLine方法用于读取一行字符串。
  • BufferedWriter提供了newLine用于写入一个行分隔符。
  • 对于缓冲流,使用flush方法会将内存中的数据立刻写出。

缓冲流相关应用

Example1

import java.io.*;
public class TestBufferedStream1 {
    public static void main(String args[]){
        try{
            FileInputStream fis=new FileInputStream("D://HelloWorld.java");
            BufferedInputStream bis =new BufferedInputStream(fis);
            int c=0;
            System.out.println(bis.read());
            System.out.println(bis.read());
            //输入fis的前两个字符
            bis.mark(100);
            for(int i=0;i<=10&&(c= bis.read())!=-1;i++){
                System.out.println(c+" ");
            }
            //依此从第三个字符开始输出十一个字符
            System.out.println(" ");
            bis.reset();
            for(int i=0;i<=10&&(c= bis.read())!=-1;i++) {
                System.out.println(c + " ");
            }
            //再输出十一个字符
            bis.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

Example2

import java.io.*;

public class TestBufferedStream2 {
    public static void main(String args[]){
        try{
            BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\JAVA\\test.txt"));
            BufferedReader br = new BufferedReader(new FileReader("D:\\HelloWorld.java"));
            String a = null;
            for(int i=1;i<=100;i++){
                a = String.valueOf(Math.random());
                bw.write(a);
                bw.newLine();
            }
            //此段代码的作用是a生成100个随机数输入到test.txt文件中
            bw.flush();
            while((a=br.readLine())!=null){
                System.out.println(a);
            }
            //将HelloWorld.java内的内容输出
            bw.close();
            br.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

结果
小黑板上的结果:
Java IO_第12张图片
文件里的结果:
Java IO_第13张图片

转换流

个人理解转换流是Reader和InputStream的转换,Writer和OutputStream的转换(本质上说就是字符流和字节流的转换吧)。
这块内容会更好理解一点点吧,现在就举一个小例子。
Example1

import java.io.*;

public class TestTransForm {
    public static void main(String args[]){
        try{
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\JAVA\\test.txt"));
            osw.write("Javahaonan!!");
            System.out.println(osw.getEncoding());
            osw.close();
            osw = new OutputStreamWriter(new FileOutputStream(("D:\\JAVA\\test.txt"),true),"ISO8859_1");
            //ISO8859_1包含所有的西欧语言,别名latin_1。
            //这个true表示Bluemsun great是加在前面的数据后面的,如果不写true就会覆盖掉前面的字符串。
            osw.write("Bluemsun great");
            System.out.println(osw.getEncoding());
            osw.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

数据流

DataInputStream和DataOutputStream分别继承自InputStream和OutputStream,它属于处理流,需要分别套接在InputStream和OutputStream类型的节点流上。
数据流提供了可以存取与机器无关的Java原始类型数据(如int,double等)的方法。
下面举一个简单的例子来阐述一下数据流的构造方法和使用。

import java.io.*;
public class TestDataStream {
    public static void main(String args[]){
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);
        //构造方法:DataOutputStream (OutputStream out);
        try{
            dos.writeDouble(Math.random());
            dos.writeBoolean(true);
            //内存里double类型的一个数据,Boolean类型一个数据
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            System.out.println(bais.available());
            //输出内存所占空间
            DataInputStream dis = new DataInputStream(bais);
            System.out.println(dis.readDouble());
            //输出double型数据
            System.out.println(dis.readBoolean());
            //输出boolean型数据
            dis.close();dos.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

结果
Java IO_第14张图片

Print流

顾名思义,Print流是用来输出的处理流。
注意事项

  • PrintWriter和PrintStream都是输出流,分别针对字符和字节。
  • PrintWriter和PrintStream提供了重载的print,println方法用于多种数据类型的输出。
  • PrintWriter和PrintStream的输出操作不会抛出异常,用户通过检测错误状态获取信息
  • PrintWriter和PrintStream有自动flush的功能。(也可以手动)

关于Print流的相关构造方法在这里不再赘述,需要学习的话可以自行打开API文档查看。
下面举一个关于Print流的应用实例。
Example

import java.io.*;
import java.util.*;
import java.util.Locale;

public class TestPrintStream3 {
    public static void main(String args[]){
        String s = null;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        try{
            FileWriter fw = new FileWriter("D:\\JAVA\\test.txt",true);
            PrintWriter pw = new PrintWriter(fw);
            while((s=br.readLine())!=null){
                if(s.equalsIgnoreCase("exit"))
                    break;
                System.out.println(s.toUpperCase());
                pw.println("-----");
                pw.println(s.toUpperCase());
                pw.flush();
                //虽然可以自动flush但是还是养成习惯flush比较好
            }
            pw.println("==="+new Date()+"===");
            pw.flush();
            pw.close();
        }catch(IOException e)
        {
            e.printStackTrace();
        }
    }
}

这个代码可以算是一个简单的写日志的代码叭。每次编辑都会显示日期,然后只有你输入才会在文件里输出。还挺有意思的。
结果看下图。
绿色是我的输入,白色是输出。Java IO_第15张图片
这是记事本内的内容。Java IO_第16张图片

Object流

Object流可以直接将Object整个写入或读出。
关于Object流先以一个例子来说明。
Example

import java.io.*;
public class TestObjectIO {
    public static void main(String args[]) throws Exception{
        T t = new T();
        t.k=8;
        FileOutputStream fos = new FileOutputStream("D:\\JAVA\\test.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(t);
        oos.flush();
        oos.close();
        FileInputStream fis = new FileInputStream("D:\\JAVA\\test.txt");
        ObjectInputStream ois = new ObjectInputStream(fis);
        T tread = (T)ois.readObject();
        System.out.println(tread.i+"  "+tread.j+" "+ tread.k+" "+ tread.n);

    }
}
class T
    implements Serializable
{
    int i = 7;
    int j = 9;
    double k = 21.0;
    transient int n = 13;
}

结果如下图:
Java IO_第17张图片
通过以上程序 Object有几个知识点需要掌握。

transient关键字
transient是流动的,暂时的的意思。它是屏蔽了在此关键词后所定义的内容,故要输出的话,会输出它的初始值,也就是0.

serializable接口
上面的程序可以看到在class T的定义中后面写了implements serializable说明该方法时可序列化的(给编译器看的),如果没有写这句话,Object整体被输入输出的话是会报错的。

externalizable接口
由serializable接口我们可以知道是可以声明一个类是可序列化的,但序列化的这个过程是由jdk来完成。而externalizable接口则可以控制序列化的过程。(但最好还是jdk给你序列化)

总结

终于写完了…这篇博客真的有够长的。上一节学异常的时候其实很懵都是在网上东拼西凑的看课预习,这节其实好很多,就看了学长学姐推荐的网课,我感觉条理很清晰。然后但是其中还是有很多细节的方法我不知道的,就一直在看API文档,比如printStackTrace,equalsIgnoreCase等。
这一节的内容其实很好分类,主要分成输出和输入两个大类,然后是节点流,处理流。节点流相对简单一点吧,File****这样的格式。处理流包括很多类,有不同功能,Buffered缓冲,转换流,Data数据流,然后是Print输出流和Object流。
还有很多方法没有写出来,需要用到的话,拥抱API叭~~~~

你可能感兴趣的:(java,后端)