Java字节流详解FileInputStream和FileOutputStream
Java 字节流详解FileInputStream 和 FileOutputStream 从入门到实践一、前言在 Java 中文件的读写操作是最基础也是最高频的 I/O 场景之一。字节流Byte Stream作为 Java I/O 体系的两大分支之一负责处理所有二进制数据的传输图片、音频、视频以及任何非文本文件都离不开它。FileInputStream和FileOutputStream是字节流中最核心的两个实现类掌握它们就掌握了 Java 文件 I/O 的基石。本文将围绕这两个类的构造、核心方法、使用方式、底层原理以及常见坑点展开确保看完后能写出健壮的文件读写代码。二、字节流简介Java 的 I/O 流分为两大类字节流Byte Stream以InputStream/OutputStream为抽象父类按字节8 bit读写适合所有类型的文件。字符流Character Stream以Reader/Writer为抽象父类按字符16 bit读写适合纯文本文件。FileInputStream和FileOutputStream分别继承自InputStream和OutputStream是操作文件的直接入口。InputStream (抽象) └── FileInputStream ← 从文件读取字节 OutputStream (抽象) └── FileOutputStream ← 向文件写入字节三、核心 API 速览3.1 FileInputStream方法签名说明FileInputStream(String name)根据文件路径创建输入流FileInputStream(File file)根据 File 对象创建输入流int read()读取一个字节返回0~255的 int读到末尾返回-1int read(byte[] b)读取最多b.length个字节到数组返回实际读取的字节数int read(byte[] b, int off, int len)读取最多len个字节到数组的指定偏移位置long skip(long n)跳过并丢弃 n 个字节int available()返回可读的字节数估计值void close()关闭流释放系统资源3.2 FileOutputStream方法签名说明FileOutputStream(String name)根据路径创建输出流覆盖模式FileOutputStream(String name, boolean append)指定是否追加模式FileOutputStream(File file)根据 File 对象创建输出流void write(int b)写入一个字节只取 int 的低 8 位void write(byte[] b)写入整个字节数组void write(byte[] b, int off, int len)写入数组的一部分void flush()刷新缓冲区字节流 flush 是空实现但遵循约定void close()关闭流释放系统资源四、代码实现4.1 基础用法单个字节读写不推荐用于大文件importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.IOException;publicclassFileInputStreamDemo{publicstaticvoidmain(String[]args)throwsIOException{// 用 try-with-resources 自动关闭流JDK 7try(FileInputStreamfisnewFileInputStream(source.txt);FileOutputStreamfosnewFileOutputStream(dest.txt)){intdata;while((datafis.read())!-1){fos.write(data);}}System.out.println(文件复制完成);}}缺点每次只读写一个字节每次 read()/write() 都涉及一次 native 调用大文件下性能极差。4.2 推荐用法字节数组批量读写importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.IOException;publicclassFileCopyWithBuffer{publicstaticvoidmain(String[]args){Stringsourcephoto.jpg;Stringdestphoto_copy.jpg;try(FileInputStreamfisnewFileInputStream(source);FileOutputStreamfosnewFileOutputStream(dest)){byte[]buffernewbyte[8192];// 8KB 缓冲区intlen;while((lenfis.read(buffer))!-1){fos.write(buffer,0,len);// 注意必须使用 write(buffer, 0, len) 而不是 write(buffer)// 因为最后一次读取可能不足 8192 字节}System.out.println(复制完成);}catch(IOExceptione){System.err.println(文件操作失败: e.getMessage());}}}4.3 追加模式写入importjava.io.FileOutputStream;importjava.io.IOException;importjava.nio.charset.StandardCharsets;publicclassFileAppendDemo{publicstaticvoidmain(String[]args){try(FileOutputStreamfosnewFileOutputStream(log.txt,true)){Stringline[System.currentTimeMillis()] 用户登录成功\n;fos.write(line.getBytes(StandardCharsets.UTF_8));}catch(IOExceptione){e.printStackTrace();}}}FileOutputStream的第二个参数append为true时写入内容追加到文件末尾而非覆盖。五、执行流程与底层原理以read(byte[])为例一次读取的完整链路如下Java 应用层调用FileInputStream.read(byte[])JDK 内部调用native readBytes方法JNI进入 C 层调用操作系统的ReadFileWindows或read()Linux/POSIX内核从磁盘读取数据到内核空间缓冲区内核 → 用户空间数据从内核缓冲区拷贝到 Java 传入的 byte 数组返回实际读取的字节数-1 表示 EOF这个过程中涉及一次用户态 ↔ 内核态切换和一次数据拷贝。这也是为什么批量读减少 native 调用次数比逐字节读快几个数量级的原因。六、常见问题与注意事项6.1 流必须关闭未关闭流会导致文件句柄泄漏最终可能触发Too many open files异常。✅ 正确做法优先使用try-with-resourcesJDK 7它会自动调用 close()即使在异常发生时也能正确关闭。6.2write(byte[])和write(byte[], 0, len)的区别fos.write(buffer)会把整个 buffer 写入文件。如果最后一次读取不足 buffer 长度会写入上一次残留的脏数据。永远使用write(buffer, 0, len)。6.4 字符编码问题字节流不涉及编码转换写入什么字节就读出什么字节。如果要在字节流上处理文本必须外部指定字符集// 写入时指定编码fos.write(中文.getBytes(StandardCharsets.UTF_8));// 读取时指定编码StringtextnewString(bytes,StandardCharsets.UTF_8);6.5 FileNotFoundException 不等于文件不存在FileInputStream构造时如果文件不存在会抛FileNotFoundException。但如果文件是个目录或者路径包含不可读的目录同一异常也会抛出。不要只把它当成文件不存在来处理。七、最佳实践能用字符流的场景纯文本用字符流否则用字节流。FileReader / FileWriter 内部封装了字节转换更省心。大文件优先用 BufferedInputStream / BufferedOutputStream包装它们在内部自动维护更大的缓冲区减少 native 调用。版本兼容检查— FileInputStream 和 FileOutputStream 从 JDK 1.0 就有不存在兼容性问题。Files.copy() 可以替代— 对于单纯复制文件java.nio.file.Files.copy()一行代码搞定底层使用更高效的 FileChannel。// NIO 一行复制Files.copy(Path.of(source.txt),Path.of(dest.txt),StandardCopyOption.REPLACE_EXISTING);八、总结FileInputStream和FileOutputStream是 Java 字节流体系中最基础的文件读写类支持所有文件类型。批量读写字节数组比逐字节读写性能高出几个数量级。始终使用try-with-resources确保流被正确关闭。写入时注意write(buffer, 0, len)而非write(buffer)避免脏数据。纯文本场景优先考虑FileReader/FileWriter或 NIO 的Files工具类。掌握字节流是理解 Java I/O 体系的第一步也是编写高可靠文件操作代码的必备基础。推荐标签Java IOFileInputStreamFileOutputStream字节流Java 文件操作
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2576747.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!