理解Java的IO流(一)——再看不懂我找不到女朋友

33 篇文章 3 订阅

不要自卑,去提升实力
互联网行业谁技术牛谁是爹
如果文章可以带给你能量,那是最好的事!请相信自己
加油o~

在这里插入图片描述

理解Java的IO流

Java的IO流是实现输入/输出的基础,它可以方便的实现数据的输入/输出操作,在Java中把不同的输入/输出源(键盘、文件、网络连接等)抽象为表述为“流”。

流(Stream)的分类

1、字节流和字符流

  • InputStream
  • Reader
  • OutputStream
  • Writer

这两种流的用法基本相似,主要是二者操纵的数据不同,字节流操作的是字节,就是那些二进制文件,而字符流一般就会处理我们能够标识的文本文件这些字符,字节流处理8位的字节,字符流处理16个字节的字符(在Java中一个字符占2个字节)

2、节点流和处理流

节点流:用于读写数据的流,有时也被称为低级流,因为它的执行效率较低

处理流:它是对现有的流进行封装,进而去执行读写等操作,这也就被称为高级流

那么我们如何去分辨一个流是节点流还是处理流呢?

一般节点流的构造参数都是物理地址,而处理流的构造参数一般为流的对象

3、输入流和输出流

输入流:顾名思义,能够从指定对象读取数据

输出流:向指定位置输出数据

一般输入流的方向是从外界到程序

而输出流是从执行程序到内存外界

四大输入输出流基类:

  • InputStream
  • Reader
  • OutStream
  • Writer

这四大类都为抽象类,是不能够实例化对象的,一般我们都是创建他们的子类对象,同时这四大类中包含很多读写方法供给使用

字节流和字符流

那么了解了这么多,我们接下来重点讲解下这两大流的使用

输入流:

InputStream的方法:

  • int read():从输入流读取单个字节,返回值为读取的字节数据
  • int read(byte[ ] arr):从输入流中读取数据存入到字节数组arr中,返回值为读取的字节数,当数据读取完成后返回-1
  • int read(byte[ ] arr,int off,int length):从输入流读取length个字节存取到字节数组中,从数组的off位置开始存储

Reader的方法:

  • int read():从输入流读取单个字符,返回值为字符所对应ASCII编码
  • int read(char[ ] arr):从输入流读取数据,存入到arr字符数组里面
  • int read(char[ ] arr,int off,int length):从输入流读取length个字符存取到字符数组中,从数组下标off开始

示例:将Java.txt文件以字节形式读取出来,并输出到控制台

//采用Java7特性,不需要手动关闭资源
try(FileInputStream fis=new FileInputStream("Java.txt")){
    byte[] arr=new byte[1024];
    int hasRead;
    while((hasRead=fis.read(arr))>0){
        System.out.println(new String(arr,0,hasRead));
    }
}

注意:这里有时会出现问题,当我们有时读取得编码未读全,就是一个字符的字节分两次读,就可能出现乱码问题,当打印的时候,如果单纯是复制文本没有问题。

try(FileReader fr=new FileReader("Java.txt")){
	char[] arr=new char[1024];
    int hasRead;
    while((hasRead=fr.read(arr))>0){
        System.out.println(new String(arr,0,hasRead));
    }
}
输出流:

OutputStream的方法:

  • void write(int a):将指定的字节输出到输出流中,其中a可以是字节,也可以是字符
  • void write(byte[ ]/char[ ] arr):将字节数组或者是字符数组中的数据写入到输出流中
  • void write(byte[ ]/char[ ] arr,int off,int length):将字符数组从下标off开始,读取length个字符存入到输出流中

Writer的方法:

  • void write(String string):将字符串string存入到输出流中
  • void write(String string,int off,int length):将指定长度的字符串输出到输出流中

示例:将 Java.txt 文件的内容复制到 Java2.txt 文件中

try(
	FileInputStream fis=new FileInputStream("Java.txt");
    FileOutputStream fos=new FileOutputStream("Java2.txt");
)
{
	byte[] arr=new byte[1024];
    int hasRead;
    while((hasRead=fis.read(arr))>0){
        fos.write(arr,0,hasRead);
    }
}

一般情况下,我们处理的是字符用字符流处理,用字节流也可以,因为字节流比较万能,字符也是由二进制转换来的

处理流的使用方法

处理流:对现有流对象进行包装,可以提高我们处理数据的效率,对于一些数据操作也会比较方便

我们讲一种很强大的流PrintStream,它的本质是字节流,他就是一种处理流,用于我们输出数据,如果我们要输出文本内容时,应该将输出流包装成PrintStream流输出

1、首先我们要创建一个输出流对象

2、创建打印流对象,传入参数,包装输出流

示例:

try(
	FileOutputStream fos=new FileOutputStream("Java.txt");
    PrintStream ps=new PrintStream(fos);
)
{
    ps.println("你好,明天");
    ps.println(new Date());
}

上述代码执行效果是,将字符串你好明天和Date类的实例对象打印到Java.txt文件中

注意:当我们关闭处理流的同时,被它包装的流也会关闭

转换流

Java提供了两个转换流

  • InputStreamReader:将字节输入流转化为字符输入流
  • OutputStreamReader:将字节输出流转化为字符输出流

我们将一个事情:在Java中,System.in代表标准输入,即键盘,而System.out表示标准输出,即控制台

有时我们可以将字节输入流转化为字符输入流

示例:本例我们将System.in转化为字符输入流,然后用BufferedReader处理流包装,加快效率

try(
	InputStreamReader isr=new InputStreamReader(System.in);
    BufferedReader br=new BufferedReader(isr);
)
{
    String line=null;
    while((line=br.readLine())!=null){
        if("exit".equals(line)){
            break;
        }else{
            System.out.println(line);
        }
    }
}

上述代码首先将标准输入流转化为字符输入流,然后用缓冲流包装,

缓冲流有readLine方法,可以读取一整行内容,本例中,就会从键盘读入一整行内容,去循环判断

重新指向标准输入输出流

对于Java我们经常通过System.in从键盘读取我们想要的内容或者用System.out向控制台输出数据,但有时我们想从文本中读取,或者是想这些数据存到文本,而不是打印到控制台,我们应该怎么办呢?

在System类中提供类两种方法:

  • void setIn(InputStream in):重新指向标准输入流,从in指定的流获取数据,而不是键盘
  • void setOut(PrintStream out):重新指向标准输出流,将输出内容输出到out输出流中,而不是控制台

示例:

try(
	PrintStream ps=new PrintStream(new FileOutputStream("Java.txt"));
)
{
    System.setOut(ps);
    System.out.println("你好明天");
    System.out.println(new Date());
}

上述代码我们讲系统的标准输出指向了PrintStream指定的流,所以之后的System.out.println等操作输出的内容就会进入文本,而不会在控制台显示,其实这可以直接用PrintStream包装指定输出流,用ps.println()也可以实现将数据写入文本

示例:

try(
	FileInputStream fis=new FileInputStream("Java.txt");
)
{
    System.setIn(fis);
    Scanner sc=new Scanner(System.in);
    sc.useDelimiter("\n");
    while(sc.hasNext()){
        System.out.println(sc.next());
    }
}

上述代码重新指定了标准输入,输入的内容不来自键盘,而是来自文本,利用循环不断判断文本是否还有数据,如果就进行读取

sc.useDelimiter("\n");

加入这句话的意思是读取内容时以回车为分界,如果不加,默认以空格为分界

强大流:RandomAccessFile流

RandomAccessFile流是Java中功能相当丰富的流,他可以实现任意读取写入数据,即支持“随机访问"。

当我们有时并不需要读取全部数据只要部分数据时,我们可以使用这种流

但是他有个缺点,他只能后操纵文本文件,不可以操纵其他流

既然他可以实现任意读取,就说明它内部存在一个指针记录真当前文件位置

  • long getFilePointer():返回文件指针的当前位置
  • void seek(long pos):将文件指针移动到pos处

它存在几个读写模式:

  1. r:以只读形式打开文件
  2. rw:以既可读也可以写的方式打开文件,如果没有自动创建

示例:读取Java.txt文件中部分数据

try(
	RandomAccessFile raf=new RandomAccessFile("Java.txt","r");
)
{
    raf.seek(100);
    byte[] arr=new byte[1024];
    int hasRead;
    while((has=raf.read(arr))>0){
        System.out.println(new String(arr,0,hasRead));
    }
}

对于基本的输入输出流的方法它全部有。

示例:向文件追加文件

try(
	RandomAccessFile raf=new RandomAccessFile("Java.txt");
)
{
    raf.seek(raf.length());
    raf.write("追加文本");
}

将指针指向文件结尾,继续写数据

那么我们如何实现插入数据呢?当我们将指针更改到指定位置,写入数据的话,后面的数据会进行覆盖,所以我们就要先保存这部分文件再还原

File tempFile=File.createTempFile("temp.txt",null);
tempFile.deleteOnExit();
try(
	RandomAccessFile raf=new RandomAccessFile(fileName,"rw");
    FileInputStream fis=new FileInputStream(tempFile);
    FileOutputStream fos=new FileOutputStream(tempFile);
)
{
    raf.seek(pos);
    byte[] arr=new byte[1024];
    int hasRead;
    while((hasRead=raf.read(arr))>0){
        fos.write(arr,0,hasRead);
    }
    raf.seek(pos);
    raf.write(InsertContent.getBytes());//将字符串转化为字节数组
    while((hasRead=fis.read(arr))>0){
        raf.write(arr,0,hasRead);
    }
}

上述代码我们定义了一个临时文件,并指定当程序结束时,自动删除

我们先将待插入位置后的文本记录到临时文件中,再去插入我们要插入的内容

之后我们再将临时文件中的内容重新写入文件中,即可完成插入操作

注意:

我们向文本追加文件也可以用这种方式:

FileWriter fw=new FileWriter("Java.txt",true);

最后一个参数代表是否追加数据

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海洋 之心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值