介绍输入输出字节流

1.IO概述


1.1什么是IO


 

生活中,你肯定经历过这样的场景。当你编辑一个文本文件,忘记了 ctrl+s,可能文件就白白编辑了。当你电脑上插入一个U盘,可以把一个视频,拷贝到你的电脑硬盘里。那么数据都是在哪些设备上的呢?键盘、内存、硬盘、外接设备等等。

我们把这种数据的传输,可以看做是一私数据的流动,按照流动的方向,以内存为基准,分为 输入input 和 输出output,即流向内存是输入流,流出内存的输出流。

Java中I/O操作主要是指使用 java.io 包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写出数据。

1.2IO的分类


根据数据的流向分为:输入流和输出流

  • 输入流:把数据从 其他设备 上读取到 内存 中的流。
  • 输出流 : 把数据从 内存 中写出到 其他设备 上的流。

格局数据的类型分为:字节流和字符流

  • 字节流 : 以字节为单位,读写数据的流。
  • 字符流 : 以字符为单位,读写数据的流。

1.3 IO的流向说明图解


 1.4顶级父类们


输入流输出流
字节流

字节输入流

InputStream

字节输出流

OutputStream

字符流

字符输入流

Reader

字符输出流

Writer

2.字节流


2.1一切皆为字节


      一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。

2.2字节输出流【OutputStream】


java.io.outputstream 抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。

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

小贴士:close方法,当完成流的操作时,必须调用此方法,释放系统资源。

OutputStream 类及其子类的对象表示一个字节输出流。OutputStream 类的常用子类如下。

  • ByteArrayOutputStream 类:向内存缓冲区的字节数组中写数据。
  • FileOutputStream 类:向文件中写数据。
  • PipedOutputStream 类:连接到一个 PipedlntputStream(管道输入流)。
  • ObjectOutputStream 类:将对象序列化。

利用 OutputStream 类的方法可以从流中写入一个或一批字节。

2.3 FileOutputStream类


outputStream 有很多子类,我们从最简单的一个子类开始。
java.io.FileOutputstream 类是文件输出流,用于将数据写出到文件。

构造方法

  • public File0utputStream(File file) :创建文件输出流以写入由指定的 File对象表示的文件。
  •  public FileOutputStream(String name) : 创建文件输出流以指定的名称写入文件。

当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有这个文件,会创建该文件。如果有这个文件,会清空这个文件的数据。

  • 构造举例,代码如下:
package Java2;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class InputTest4 {
    public static void main(String[] args) throws FileNotFoundException {
        //使用File对象创建流对象
        File file=new File("a.txt");
        FileOutputStream fos=new FileOutputStream(file);

        //使用文件名称创建流对象
        FileOutputStream fos1=new FileOutputStream("b.txt");
    }
}

写出字节数据

  • 写出字节 : write(int b) 方法,每次可以写出一个字节数据,代码使用演示:
package Java2;

import java.io.*;

public class OutPutTest1 {
    public static void main(String[] args) throws IOException {
        File f1=new File("d:/aa");
        File f2=new File(f1,"a.txt");
        f1.mkdirs();
        f2.createNewFile();
        //使用OutPutStream输出流完成对文件的写入操作内存输出到文件
        OutputStream out=new FileOutputStream(f2);
        //out.write(97); //按照解析数字 写入文件中 写入的是97对应的 a

        //out.write(bytes); //按照ASCII解析数组 写入文件 写入的: abcdefg
        // 写出数据
        out.write(97);//写出第1个字节
        out.write(98);//写出第2个字节
        out.write(99);//写出第3个字节

    }
}

输出结果:
abc


  • 写出指定长度字节数组: write(byte[] b,int off,int len) ,每次写出从off索引开始,len个字节,代码使用演示:
package Java2;

import java.io.*;

public class OutPutTest2 {
    public static void main(String[] args) throws IOException {
        File f1=new File("d:/");
        File f2=new File(f1,"a.txt");
        f1.mkdirs();
        f2.createNewFile();

        //使用OutPutStream输出流完成对文件的写入操作内存输出到文件
        OutputStream out=new FileOutputStream(f2);
        //out.write(97); //按照解析数字 写入文件中 写入的是97对应的 a
        byte[] bytes={97,98,99,100,101,102,103};
        //out.write(bytes); //按照ASCII解析数组 写入文件 写入的: abcdefg
        out.write(bytes,2,3);
    }
}

输出结果:
cde

数据追加续写

经过以上的演示,每次程序运行,创建输出流对象,都会清空目标文件中的数据。如何保留目标文件中数据,还能继续添加新数据呢 ?

  • public FileoutputStream(File file boolean append) : 创建文件输出流以写入由指定的 File对象表示的文件。
  • public Fileoutputstream(String name, boolean append) : 创建文件输出流以指定的名称写入文件。

这两个构造方法,参数中都需要传入一个boolean类型的值,true 表示追加数据,fase 表示清空原有数据。这样创建的输出流对象,就可以指定是否追加续写了,代码使用演示:

package Java2;

import javax.sound.midi.Soundbank;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;

public class OutPutTest3 {
    public static void main(String[] args) throws IOException {
        File f1=new File("d:/春.txt");
        f1.createNewFile();

        //第二个参数指定为true表示追加数据,否则是清空后写入数据(默认)
        OutputStream out=new FileOutputStream(f1,true);

        String msg="盼望着";
        byte[] bytes=msg.getBytes();//获取字符串 解析后的 byte数组
        System.out.println(Arrays.toString(bytes));
        out.write(bytes);//把byte数组写入文件,相当于把字符串写入文件中
    }
}

输出结果:
[-25, -101, -68, -26, -100, -101, -25, -99, -128]

写出换行

Windows系统里,换行符号是\r\n.

把以指定是否追加续写了,代码使用演示:

public class OutPutTest3 {
    public static void main(String[] args) throws IOException {
        File f1=new File("d:/春.txt");
        f1.createNewFile();

        OutputStream out=new FileOutputStream(f1);

        String msg="盼望着";
        byte[] bytes=msg.getBytes();//获取字符串 解析后的 byte数组

        out.write(bytes);//把byte数组写入文件,相当于把字符串写入文件中
        out.write("\n.".getBytes());
        out.write("第二行".getBytes());
    }
}

输出结果:
盼望着
第二行

回车符\r和换行符\n:

  • 回车符:回到一行的开头(return)。
  • 换行符:下一行(newline)。

系统中的换行:

  • Windows系统里,每行结尾是 回车+换行 ,即\r\n ;
  • Unix系统里,每行结尾只有 换行 ,即\n ;
  • Mac系统里,每行结尾是 回车 ,即 \r 。从 Mac OS X开始与Linux统一。

2.4字节输入流【InputStream】


java.io.InputStream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。

  • public void close() : 关闭此输入流并释放与此流相关联的任何系统资源。
  • public abstract int read() : 从输入流读取数据的下一个字节。
  • public int read(byte[] b) : 从输入流中读取一些字节数,并将它们存储到字节数组 b中。

InputStream 类及其子类的对象表示字节输入流,InputStream 类的常用子类如下:

  • ByteArrayInputStream 类:将字节数组转换为字节输入流,从中读取字节。
  • FileInputStream 类:从文件中读取数据。
  • PipedInputStream 类:连接到一个 PipedOutputStream(管道输出流)。
  • SequenceInputStream 类:将多个字节输入流串联成一个字节输入流。
  • ObjectInputStream 类:将对象反序列化。

小贴士:close方法,当完成流的操作时,必须调用此方法,释放系统资源。

使用 InputStream 类的方法可以从流中读取一个或一批字节。

                                                  InputStream类的常用方法

方法名及返回值类型说明
int read()从输入流中读取一个 8 位的字节,并把它转换为 0~255 的整数,最后返回整数。
如果返回 -1,则表示已经到了输入流的末尾。为了提高 I/O 操作的效率,建议尽量
使用 read() 方法的另外两种形式
int read(byte[] b)从输入流中读取若干字节,并把它们保存到参数 b 指定的字节数组中。 该方法返回
读取的字节数。如果返回 -1,则表示已经到了输入流的末尾
int read(byte[] b, int off, int len)从输入流中读取若干字节,并把它们保存到参数 b 指定的字节数组中。其中,off 指
定在字节数组中开始保存数据的起始下标;len 指定读取的字节数。该方法返回实际
读取的字节数。如果返回 -1,则表示已经到了输入流的末尾
void close()关闭输入流。在读操作完成后,应该关闭输入流,系统将会释放与这个输入流相关
的资源。注意,InputStream 类本身的 close() 方法不执行任何操作,但是它的许多
子类重写了 close() 方法
int available()返回可以从输入流中读取的字节数
long skip(long n)从输入流中跳过参数 n 指定数目的字节。该方法返回跳过的字节数
void mark(int readLimit)在输入流的当前位置开始设置标记,参数 readLimit 则指定了最多被设置标记的字
节数
boolean markSupported()判断当前输入流是否允许设置标记,是则返回 true,否则返回 false
void reset()将输入流的指针返回到设置标记的起始处

注意:在使用 mark() 方法和 reset() 方法之前,需要判断该文件系统是否支持这两个方法,以避免对程序造成影响。

代码如下:

import java.io.*;

public class InputTest1 {
    public static void main(String[] args) throws IOException {
        //输出流:内存的内容输出到文件(写操作)输入流:文件内容输入到内存中(读操作)
        File f1=new File("d:/春.txt");
        //创建一个输入流,读取f1这个文件
        InputStream input=new FileInputStream(f1);
        //读取文件的一个字符,然后把字符转换为对应的数字返回。如果读取到文件的末尾,返回的是-1
        int n;
        while ((n=input.read())!=-1){
            System.out.println((char)n);
        }

    }
}

2.5FilelnputStream类


java.io.FileInputstream 类是文件输入流,从文件中读取字节。

FileInputStream 是 Java 流中比较常用的一种,它表示从文件系统的某个文件中获取输入字节。通过使用 FileInputStream 可以访问文件中的一个字节、一批字节或整个文件。

在创建 FileInputStream 类的对象时,如果找不到指定的文件将拋出 FileNotFoundException 异常,该异常必须捕获或声明拋出。

FileInputStream 常用的构造方法主要有如下两种重载形式。

构造方法

  • FileInputStream(File file) : 通过打开与实际文件的连接来创建一个FilelnputStream,该文件由文件系统中的 File对象 file命名。
  • FileInputstream(String name) : 通过打开与实际文件的连接来创建一个 FilelnputStream,该文件由文件系统中的路径名 name命名。

当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有该文件,会抛出 FileNotFoundException。

构造举例,代码如下 :

例:假设有一个D:\my\HelloJava.java 文件,下面使用 FileInputStream 类读取并输出该文件的内容。代码如下:

​
public class Test1 {
public static void main(String[] args) {
File f = new File("D:/my/HelloJava.java");
FileInputStream fis = null;
try {
// 因为File没有读写的能力,所以需要有个InputStream
fis = new FileInputStream(f);
// 定义一个字节数组
byte[] bytes = new byte[1024];
int n = 0; // 得到实际读取到的字节数
System.out.println("D:\\my\\HelloJava.java文件内容如下:");
// 循环读取
while ((n = fis.read(bytes)) != -1) {
String s = new String(bytes, 0, n); // 将数组中从下标0到n的内容给s
System.out.println(s);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
 
​

注意:FileInputStream 类重写了父类 InputStream 中的 read() 方法、skip() 方法、available() 方法和 close() 方法,不支持 mark() 方法和 reset() 方法。

2.6复制原理截图


 案例实现

package Java2;

import java.io.*;

public class CopyFileTest1 {
    public static void main(String[] args) throws IOException {
        //1.定义源文件和目的文件的文件对象
        File f1=new File("D:/a.jpg");
        File newFile=new File("D:/aa/copy.jpg");

        //2.创建目的文件
        newFile.createNewFile();

        //3.定义输入输出流:使用输入流读取内容 使用输出流写入内容
        InputStream in=new FileInputStream(f1);
        OutputStream out=new FileOutputStream(newFile);

        //练习是容易理解的方式
        byte[] buffe=new byte[10];
        int n=0;
        while (true){
            n=in.read(buffe);//读取文件,内容放入buffer数组中,返回的是实际读取的字节数
            if (n!=-1){
                out.write(buffe,0,n);//把buffer数组从0开始,截取读取到有效字节数n 写入到目的文件中
            }else {
                break;
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值