学好JAVA基础(六):I/O流

 流是一种抽象概念,它代表了数据的无结构化传递。

百度百科

I/O的表面意思是什么?

I流 - InputSteam    输入流

    O流 - OutPutStream 输出流

    这就是我们常说的I/O流,根据其它条件,我们又划分为以下几种类型

    按照数据传递方向分为:输入流、输出流

      按照数据传递类型分为:字符流、字节流

      友善解释一下,字符和字节的区别:

字节(Byte):,计算机处理的基本单位,简写B,1B = 8Bit(位)
字符:指的是计算机中使用过的字母、字、数字、符号等 
  ASCIIS码:英文字母(不分大小写)= 1B
            中文汉字 = 2B
            ASCII码 = 1B
  UTF-8编码:英文字符 = 1B
            英文标点  = 1B
            中文(含繁体) = 3B
            中文标点 = 3B
  Unicode编码:英文字符 = 2B
              英文标点  = 2B
              中文(含繁体) = 2B
              中文标点 = 2B

      JAVA中I/O模型为Decorator(装饰者)模式,支持了许多功能的Stream,我们可以按照我们的需求来动态使用。

比如,您要读写一个文件,就可以选择FileInputStream和BufferedInputStream。

另外,我们也看到,I/O流的接口和实现类众多,所以我们选择其中的几个常见常用的来了解一下。

01

字节流的输入输出

字节输入流

不包含边界数据的连续流。

百度百科

        任何数据的读取或者写入都是有目标的,I/O流也不例外,这里我们以文件为例,进行读取写入操作。

         首先,我们在D盘下创建一个文件:student.txt,并写入内容:name:bob

          然后,我们选择用FileInputStream这个类获取文件的内容。因为会用到read方法,我们首先来看下他的源码注释

* Reads a byte of data from this input stream. This method blocks      * if no input is yet available.      * @return     the next byte of data, or <code>-1</code> if the end of the      *             file is reached.      * @exception  IOException  if an I/O error occurs.

大致意思就是:从这个输入流读取数据,如果没有数据,则返回 -1。好了,现在我们已经知道了规则,开始代码吧。

File file = new File("D:/student.txt");
  FileInputStream fileInputStream = new FileInputStream(file);
  int i = fileInputStream.read();
  while (i > 0){
      System.out.print((char)i);
      i = fileInputStream.read();
  }
  //输出j结果
  name:bob

         很幸运,我们第一次成功了。按照程序的执行顺序我们看到,程序读一个写一个,如果文件足够长,岂不是效率会被拖死。那么,有没有一种好的方式解决这个问题呢?

你看,它提供了一个read的有参方法。注释大意就是,参数b作为一个缓冲区,会返回读入缓冲区的字符总数,然后读完返回 -1。

好吧,我们试一试。

File file = new File("D:/study/student.txt");
    FileInputStream fileInputStream = new FileInputStream(file);
    //代表每四个字节
    byte[] b = new byte[4];
    int i = fileInputStream.read(b);
    while (i > 0){
      String str = new String(b);
        System.out.println(str);
            i = fileInputStream.read(b);
        }     

输出结果:

我们很清晰的发现,它换行了,说明它每次都会读取四个字节在返回,所以是很实用的。日常工作中,为了保证正常合理的配置,建议将缓存区设置为【1024】,若有特殊需要可自行进行调节。(以下缓存区更换为1024)

可能这是你会问了,如果文件中出现中文,还能正常读吗?说的多不如一做,来,我们实践一下,看看会发生什么结果?

在刚才的【student.txt】中写入 -  job:程序猿

运行结果:

乱码了,咋整?没关系,我们可以转化一下

File file = new File("D:/study/student.txt");
FileInputStream fileInputStream = new FileInputStream(file);
byte[] b = new byte[1024];
int i = fileInputStream.read(b);
while (i > 0){
  String str = new String(b,"UTF-8");
    System.out.print(str);
        i = fileInputStream.read(b);
    }

你看输出结果:

你看,多好

字节输出流

    你用的人家的FileInputStream类,当然要用FileOutputStream类来输出一下,毕竟要表示尊敬,是吧?

我们先理清一下操作逻辑,我们既然要输出一下我们读取的信息,自然要有一个接收方,这里,我们创建一个【teacher.txt】来接收。

首先,我们先看一下它的源码,有哪些方法。

FileInputStream提供了众多的有参构造方法,比如

//创建名称为 name 值的文件
public FileOutputStream(String name) throws FileNotFoundException {
        this(name != null ? new File(name) : null, false);
    }
//创建名称为 name 值的文件, 
//append:顾名思义j就是是否增加,如果是ture,内容将在文件的尾部增加,否则则是覆盖
public FileOutputStream(String name, boolean append)
    throws FileNotFoundException
{
    this(name != null ? new File(name) : null, append);
}

其余的方法不说,我们就用第一个吧,上代码。

File file = new File("D:/study/student.txt");
FileInputStream fileInputStream = new FileInputStream(file);
byte[] b = new byte[1024];
int i = fileInputStream.read(b);
while (i > 0){
      String str = new String(b,"UTF-8");
        i = fileInputStream.read(b);
    }
File outfile = new File("D:/study/teacher.txt");
FileOutputStream fileOutputStream = new FileOutputStream(outfile,false);
//读是read,写当然就是write了
fileOutputStream.write(b);

运行完成,打开我们的【teacher.txt】文件

收工。

  

02


字符流的输入输出

字符输入流

在字节流的基础上,加上编码,形成的数据流

百度百科

Reader :字符输入流常见的几个

  1. BufferedReader

  2. FileReader

  3. InputStremReader

  接下来,我们以InputStremReader为例,操作一下。

File file = new File("D:/study/student.txt");
FileInputStream fileInputStream = newFileInputStream(file);
//获取字符输入流
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"utf-8");
char[] c = newchar[1024];
intread = inputStreamReader.read(c);
System.out.println( newString(c));

看看结果呢?

so easy?

    

字符输出流

Writer:上面,我们用InputStremReader进行了读取,因此,我们也对应的使用OutputStreamWriter进行写入。

File file = new File("D:/study/student.txt");
FileInputStream fileInputStream = newFileInputStream(file);
//获取字符输入流
InputStreamReader inputStreamReader = newInputStreamReader(fileInputStream,"utf-8");
char[] c = newchar[1024];
intread = inputStreamReader.read(c);
File file1 = newFile("D:/study/teacher.txt");
OutputStream outputStream = newFileOutputStream(file1);
OutputStreamWriter outputStreamWriter = newOutputStreamWriter(outputStream,"utf-8");
outputStreamWriter.write(c);
outputStreamWriter.flush();
outputStreamWriter.close();

我们接着去看【teacher.txt】的结果

如你所愿,成功的写入到了你的新文件。


貌似是说完了,但是我们还有两个问题。


1.以上都是文本文件,若是图片,怎么进行读取和写入

其实这个问题,我们首先要考虑的是两种文件的本质读取方式是什么?才会使我们解决的方式更加科学。

文本文件:是指那些内容为纯文本的文件

二进制文件:图形文件及文字处理程序等计算机程序都属于二进制文件。

其实说直白点,图片、音频、视频,这些都是二进制文件,从根本上来说,文本文件也是二进制文件的一种。

然后,我们在去了解一下字节流和字符流的特点。

字节流,是可以操作二进制文件的,因为 1Byte = 8bit,比如数字,字母都是一个字节,但是中文的话,占用两个字节,就会出现读取不全的情况。你可以在上面字节输入输出流的例子中里,把读取写入的长度都调整为4,你在看结果,会有一个很好的展现。

字符流,正好可以解决上面的问题,因为它操作的单位是字符。

所以,我们必须字节流去处理二进制文件

File file = new File("D:/study/student.jpg");
BufferedImage bufferedImage = ImageIO.read(file);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();    
ImageIO.write(bufferedImage, "jpg", byteArrayOutputStream);    
byte[] bytes = byteArrayOutputStream.toByteArray();   
ByteArrayInputStream bais = newByteArrayInputStream(bytes);    
BufferedImage bufferedImage2 =ImageIO.read(bais); 
//可以是jpg,png,gif格式  
File file2 = newFile("D:/study/teacher.png");  
ImageIO.write(bufferedImage2, "jpg", file2);

自己运行的时候,只需要把地址换成你的文件地址就可以了。

ByteArrayOutputStream

FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。

ImageIO 提供了读取和写入图片的基本方法


2.Buffered缓冲流的实际应用有什么好处?特点是什么?

不管是字节流还是字符流,都提供了缓冲流。

BufferedInputStrean 

BufferedOutputStream

BufferedReader

BufferedWriter

      都是常见的缓冲流,缓冲流的作用,就是避免频繁读写硬盘。

      缓冲流中最具有特色的方法就是它的:readLine方法。另外,前面两种流中,都增加了synchronized关键字读写方法。我们来分别看一下它的源码。

//BufferedInputStrean 
public synchronized int read() throws IOException {
        if (pos >= count) {
            fill();
            if (pos >= count)
                return -1;
        }
        return getBufIfOpen()[pos++] & 0xff;
    }
 //BufferedOutputStream
 public synchronized void write(int b) throws IOException {
        if (count >= buf.length) {
            flushBuffer();
        }
        buf[count++] = (byte)b;
    }

BufferedInputStrean

BufferedOutputStream

我们看到这两种流支持了读写的线程安全操作。


BufferedReader:

//BufferedReader
 public String readLine() throws IOException {
        return readLine(false);
    }

 再去看它的注释:

读取该行的文本并返回。


以上都是一些缓冲流的独特的方法,那么他们在现实意义中有什么作用呢?其实可以把它们当比喻我们秋收玉米。

正常的读取文件的方式,类似于,你掰一个玉米,放一次家里,然后接着在进行往复的重复操作,这样做,大量的时间消耗在路上,大大降低了效率。

缓冲流,就是你掰好了玉米,然后用拖拉机拉走,一拉一车,然后重复操作,这样就大大的减少了往返的时间,提高了效率。


最后,求一波关注。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

KeepMoving00

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

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

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

打赏作者

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

抵扣说明:

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

余额充值