基本文件字节流FileInputStream、FileOutputStream

1,968 阅读6分钟

这是我参与8月更文挑战的第29天,活动详情查看:8月更文挑战

详细介绍了Java IO中的基本文件字节流FileInputStream、FileOutputStream的方法以及使用方式。

1 FileInputStream文件字节输入流

public abstract class InputStream
extends Object
implements Closeable

此抽象类是表示字节输入流的所有类的超类。需要定义 InputStream 子类的应用程序必须总是提供返回下一个输入字节的方法。

public class FileInputStream
extends InputStream

和文件相关的字节输入流,读取文件字节数据。

1.1 构造器

public FileInputStream(String name)

创建一个对象,创建的时候,指定一个抽象路径。如果指定文件不存在,或者它是一个目录,而不是一个常规文件,抑或因为其他某些原因而无法打开进行读取,则抛出 FileNotFoundException。

public FileInputStream(File file)

通过打开一个到实际文件的连接来创建一个 FileInputStream。如果指定文件不存在,或者它是一个目录,而不是一个常规文件,抑或因为其他某些原因而无法打开进行读取,则抛出 FileNotFoundException。

1.2 API方法

public abstract int read()

一次读取一个字节,能够读取英文。读取中文时,会出现乱码,因为中文占两个字节,一次只能读取半个汉字。

返回 0 到 255 范围内的 int类型字节Unicode值;如果到达流的末尾,则返回-1。

public int read(byte[] b)

从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。

返回一次读入缓冲区的总字节数;如果因为已经到达流末尾而不再有数据可用,则返回 -1,即读取到的字节数为-1。缓冲区的字节将会被后面读入的字节重索引0开始一一覆盖!

public int available()

返回文件当中剩余(未读取)的字节个数。

public void close()

1.2.1 补充

使用字节流读取文件时:

  1. 使用read()方法,不能直接读取中文,因为中文占两个字节,而read读取一个字节。
  2. 使用read(byte b[])方法,可能会读取不到中文(数组最后索引为中文)。
  3. 使用available和read(byte b [])结合,可以读取中文,但是如果文件过大,可能会造成内存溢出,导致程序卡顿等问题。因此适用于自己明确文件大小不会很大的时候。

2 FileOutputStream文件字节输出流

public abstract class OutputStream
extends Object
implements Closeable, Flushable

OutputStream抽象类是所有字节输出流的基类。

public class FileOutputStream
extends OutputStream

和文件相关的字节输出流,向文件输出字节数据。

2.1 构造器

public FileOutputStream(String name)

创建具有指定名称的文件,指定一个字符串抽象路径。路径文件不存在,则创建;存在,则覆盖;指定路径的盘符不存在或者文件是目录则不创建并抛出异常。以下三个构造器同理!等同于调用FileOutputStream(name,false);

public FileOutputStream(String name,boolean append)

创建具有指定名称的文件,指定一个字符串抽象路径。append:如果为 true,则将字节写入文件末尾处,而不是写入文件开始处,即追加写文件而不是覆盖。

public FileOutputStream(File file)

创建一个向指定 File 对象表示的文件中写入数据的文件输出流。

public FileOutputStream(File file,boolean append)

创建一个向指定 File 对象表示的文件中写入数据的文件输出流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。创建一个新 FileDescriptor 对象来表示此文件连接。

2.2 API方法

public void write(int b)

将指定的字节写入此输出流。

要写入的字节是参数b的八个低位,b 的24个高位将被忽略。因为参数类型是int,它是一个32位二进制数,占4个字节,而一个字节只需要占8位,要转换为Unicode对应字符输出,因此只需要取低位8位即可。

public void write(byte[] b)

将 b.length 个字节从指定的 byte 数组写入此输出流。等效于调用 write(b, 0, b.length)

public void write(byte[] b,int off,int len)

将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。

将数组 b 中的某些字节按顺序写入输出流:元素 b[off] 是此操作写入的第一个字节,b[off+len-1] 是此操作写入的最后一个字节。

public void flush();
public void close();

2.2.1 补充

计算机是如何识别什么时候该把两个字节转换为一个中文呢?

在计算机中,中文的存储分两个字节:

第一个字节肯定是负数。第二个字节常见的是负数,可能有正数。但是没影响。即计算机读到负数就会把该数和后面的数拼起来,然后再去编码表里面查询即可转换为中文展示出来。

3 案例

3.1 写入文件

public class FileOutputStreamDemo01 {
    
    public static void main(String[] args) throws IOException {
        FileOutputStream fo = new FileOutputStream("C:\\Users\\lx\\Desktop\\test.txt");
        String test = "Aa你好呀";
        byte[] bytes = test.getBytes();
        System.out.println(Arrays.toString(bytes));
        //写字节
        fo.write(bytes);
        fo.flush();
        fo.close();
    }


    /**
     * 追加写入
     */
    @Test
    public void test1() throws IOException {
        FileOutputStream fo = new FileOutputStream("C:\\Users\\lx\\Desktop\\test.txt", true);
        String test = "aA你好呀";
        byte[] bytes = test.getBytes();
        for (byte aByte : bytes) {
            fo.write(aByte);
        }
        fo.flush();
        fo.close();
    }

}

3.2 读取文件

字节流可以操作任何类型的文件,如果要读取文件文件,只需要先读取文件的字节数据,然后将字节数组转换为String字符串即可。

public class FileInputStreamdemo01 {
    public static void main(String[] args) throws IOException {
        FileInputStream fi = new FileInputStream("C:\\Users\\lx\\Desktop\\test.txt");
        int i;
   /*while((i=fi.read())!=-1)
   {
       System.out.print((char)i);    //返回的是一个字节的字符的ASCII值,打印应该转换为字符    不能读取中文
   }*/

   /*byte []by=new byte[3];
   while ((i=fi.read(by))!=-1)
   {
       System.out.print(new String(by,0,i));             //可能读取不到中文
   }*/

        //一次读取全部,能读取中文,但是如果文件过大会造成内存溢出.
        byte[] by = new byte[fi.available()];
        while ((i = fi.read(by)) != -1) {
            System.out.print(new String(by, 0, i));
        }
        fi.close();
    }
}

3.3 拷贝文件

使用字节流可以操作任何类型的文件,除了文本文件之外,这里的拷贝还可以拷贝图片、视频等等非文本类型的文件。

public class CopyFile {

    public static void main(String[] args) {
        //拷贝图片测试
        String str1 = "C:\\Users\\lx\\Desktop\\test.jpg";
        String str2 = "C:\\Users\\lx\\Desktop\\test2.jpg";
        // copy(str1, str2);

        //拷贝视频测试
        String str3 = "C:\\Users\\lx\\Desktop\\test.wmv";
        String str4 = "C:\\Users\\lx\\Desktop\\test2.wmv";
        copy(str3, str4);
    }

    public static void copy(String str1, String str2) {
        FileInputStream fi = null;
        FileOutputStream fo = null;
        try {
            fi = new FileInputStream(str1);
            fo = new FileOutputStream(str2);
            byte[] by = new byte[1024];
            int i;
            while ((i = fi.read(by)) != -1) {
                fo.write(by, 0, i);
                fo.flush();
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fi != null) {
                try {
                    fi.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fo != null) {
                try {
                    fo.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!