Java IO基础(同步阻塞IO)

简介: Java IO是一套Java 用来读写数据(输入和输出)的API,大部分程序都需要处理一些输入,并由输入产生一些输出(PS: 输入和输出是相对CPU而言的,input 就是从外面到CPU,output就是从CPU到外面,CPU是主人公)。java.io 包下有大约80多个类,大概可以分成四组:

概述

Java IO是一套Java 用来读写数据(输入和输出)的API,大部分程序都需要处理一些输入,并由输入产生一些输出(PS: 输入和输出是相对CPU而言的,input 就是从外面到CPU,output就是从CPU到外面,CPU是主人公)。java.io 包下有大约80多个类,大概可以分成四组:

1.基于字节操作的I/O接口: InputStream和OutputStream

2.基于字符操作的I/O接口:Writer和Reader

3.基于磁盘操作的I/O接口:File

4.基于网络操作的I/O接口:Socket

java.io 包下的类如下:

1aa45a1ae823cc916ac66629d0ad17d4_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1MzQ4MDg=,size_16,color_FFFFFF,t_70.png

File类

Java IO API中的File类可以让你访问底层文件系统,通过File类。你可以做到如下几点:

1.检测文件是否存在 (file.exists())

2.读取文件长度 (file.length())

3.重命名或者移动文件(file.renameTo(new File(“c:\data\new-file.txt”));)

4.删除文件(file.delete())

5.检测某个路径是文件还是目录。(file.isDirectory())

6.读取目录中的文件列表。(String[] fileNames = file.list())

PS: 在项目中用相对路径读取文件

运用相对路径读取文件,其实就是要找到Java编译(class 文件所在的目录)后的存放目录,然后在该目录下找文件。读取方法有如下两种。

public class RelativePath {
    public static void main(String[] args) {
//        方法一
        String fileName = ReaderTest.class.getResource("/inputTest.txt").getFile();
        System.out.println("*****方法一相对路径读取到的文件地址:"+fileName);
//        方法二
        String fileName1 = Thread.currentThread().getContextClassLoader().getResource("inputTest.txt").getFile();
        System.out.println("*****方法二相对路径读取到的文件地址:"+fileName1);
    }
}

运行结果:

401ccceeae00b9a9d3926613520b8579_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1MzQ4MDg=,size_16,color_FFFFFF,t_70.png

输入和输出

输入流 用来表示那些从不同数据源产生输入的类。这些数据源包括:

1.字节数组

2.String 对象

3.文件

4.“管道”,工作方式与实际管道类似,即,从一端输入,从另一端输出

5.一个由其他种类的流组成的序列,以便我们可以将它们收集合并到一个流内

输出流: 决定输出所要去往的目标,目标包括:

字节数组

文件

管道

基于字节操作的I/O接口: InputStream和OutputStream

InputStream 的类图

ea47771e94902b8401924e3be897de08_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1MzQ4MDg=,size_16,color_FFFFFF,t_70.png

每个子类的功能以及使用如下图表所示:

8df66266d03ef706a0a834a078624638_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1MzQ4MDg=,size_16,color_FFFFFF,t_70.png

运用InputStream的实现类读取文件

1.方法1️⃣

/**
     * 以字节为单位读取文件,常用于读二进制文件,如图片、声音、影像等文件。
     * 当然也是可以读字符串的。
     *
     * @param fileName
     */
    public static void readString1(String fileName) throws IOException {
//        FileInputStream 用于读取诸如图像数据之类的原始字节流,读取字符流,请使用FileReader
        InputStream is = new FileInputStream(fileName);
        StringBuilder stringBuilder;
        try {
            stringBuilder = new StringBuilder();
            byte[] bytes = new byte[1024];
            int len;
            while ((len=is.read(bytes))>0) {
                stringBuilder.append(bytes,0,len);
            }
        } finally {
            if (is != null) {
                is.close();
            }
        }
        System.out.println("读取到的结果:" + stringBuilder.toString());
    }

2.方法2️⃣

 

/**
     * 按字节读取字符串,一次性读取完
     * @param fileName
     * @throws IOException
     */
    public static void readString2(String fileName) throws IOException {
        InputStream inputStream = new FileInputStream(fileName);
        try {
            // size  为字串的长度 ,这里一次性读完
            byte[] bytes = new byte[inputStream.available()];
            inputStream.read(bytes);
            System.out.println("读取到的结果是:"+new String(bytes,"UTF-8"));
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

按行读取数据

InputStreamReader   inputStreamReader = new InputStreamReader(new FileInputStream(file),"UTF-8");
         BufferedReader  bufferedReader = new BufferedReader(inputStreamReader);
      while (StringUtils.isNotBlank(line = bufferedReader.readLine())) {
          System.out.println("读取到的结果是:"+line);
     }

OutputStream 的类图

b187d7fa4e724786ffde5280cd98e513_20190609203902434.png

每个子类的功能和使用如下图表所示:

a906029aa841ecaadc599af58e9bcfb8_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1MzQ4MDg=,size_16,color_FFFFFF,t_70.png

运用OutputStream的实现类写入文件

1.方法1️⃣

使用FileOutputStream进行写入。

/**
     * 使用FileOutputStream
     * @param file
     * @throws IOException
     */
    public static void  writeStringToFile1(File file) throws IOException {
        FileOutputStream fos = new FileOutputStream(file);
        try {
            fos.write("www.jay".getBytes());
            fos.flush();
        } finally {
            if (fos != null) {
                fos.close();
            }
        }
    }

2.方法2️⃣

使用PrintStream进行写入

/**
     * 使用PrintStream写入
     * @param file
     * @throws FileNotFoundException
     */
    public static void writeStringToFile2(File file) throws FileNotFoundException {
        PrintStream printStream = null;
        try {
            printStream = new PrintStream(new FileOutputStream(file));
            printStream.append("你好");
            printStream.append("java");
        } finally {
            if (printStream != null) {
                printStream.close();
            }
        }
    }

3.方法3

通过 IOUtil 进行数据操作

ByteArrayOutputStream outputStream  = new ByteArrayOutputStream();
   IOUtils.copy(inputStream, outputStream);
   byte[]  buffer=outputStream.toByteArray()

或者

byte[] buff = new byte[1024];
        BufferedInputStream bis = null;
        OutputStream os = null;
        try {
            os = new ByteArrayOutputStream();
            bis = new BufferedInputStream(stream);
            int len;
            while ((len = bis.read(buff)) >0) {
                os.write(buff, 0, len);
            }
              os.flush();
        }catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                IOUtils.closeQuietly(bis);
            }
            IOUtils.closeQuietly(os);
        }

基于字符操作的I/O接口:Writer和Reader

Reader 和Writer 与InputStream和OutputStream 的最大区别是,InputStream和OutputStream是基于字节操作的I/O接口。而Reader 和Writer是基于字符操作I/O 接口。通过InputStreamReader适配器可以把InpuStream转换成Reader。通过OutputStreamWriter 适配器可以把OutputStream 转换成Writer。

如下图表示在两个继承层次结构中,信息的来源于去处。

17f8b3b90abaa960cb55cd3e46687f8a_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1MzQ4MDg=,size_16,color_FFFFFF,t_70.png

Reader 的类图

0655d1e44825908e02c8bb0cdc7c411f_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1MzQ4MDg=,size_16,color_FFFFFF,t_70.png

运用Reader的实现类读取文件内容(只能读取字符流)

1.方法1️⃣

 

public static void readFileToString1(String fileName ) throws IOException {
        File file = new File(fileName);
        FileReader fileReader = new FileReader(file);
        int length = Integer.valueOf(String.valueOf(file.length()));
  //定义一个大小等于文件大小的字符数组
        char[] chars = new char[length];
        StringBuilder str = new StringBuilder();
        try {
            int data;
            while ((data=fileReader.read(chars))>0) {
                System.out.println("读取到的字符是="+data);
                str.append(chars);
            }
            System.out.println("读取到的结果:"+str.toString());
        } finally {
            if (fileReader != null) {
                fileReader.close();
            }
        }
    }

2.方法2️⃣

/**
     * InputStreamReader+BufferedReader读取字符串 ,
     * InputStreamReader类是从字节流到字符流的桥梁,
     * 按行读对于要处理的格式化数据是一种读取的好方式
     * @param fileName
     * @throws IOException
     */
    public static void readFileToString2(String fileName) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new FileReader(fileName));
        try {
            StringBuilder stringBuilder = new StringBuilder();
            String data = null;
            while ((data = bufferedReader.readLine()) != null) {
                stringBuilder.append(data);
            }
            System.out.println("读取到的结果:"+stringBuilder.toString());
        } finally {
            if (bufferedReader != null) {
                bufferedReader.close();
            }
        }
    }

Writer 的类图

98bf0b4717c25b8528521809cc5f246e_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1MzQ4MDg=,size_16,color_FFFFFF,t_70.png

运用Writer的实现类写入内容到文件

1.方法1️⃣

/**
     * 使用BufferedWriter写入
     * @param file
     * @throws IOException
     */
    public static void writeStringToFile1(FileWriter file) throws IOException {
        BufferedWriter bufferedWriter = new BufferedWriter(file);
        bufferedWriter.append("bufferedWriter");
        bufferedWriter.append("测试2111");
        bufferedWriter.close();
    }

2.方法2️⃣

/**
     * 使用PrintWriter写入
     * @param fileWriter
     * @throws IOException
     */
    public static void writeStringToFile2(FileWriter fileWriter) throws IOException {
        PrintWriter printWriter = new PrintWriter(fileWriter);
        printWriter.append("printWriter");
        printWriter.append("实验");
        printWriter.close();
    }

3.方法三

利用字节流向文件中写入数据。

//创建文件
        File file = new File("test.txt");
        //写入数据
        OutputStream os = null;
        try {
            os = new FileOutputStream(file);
            String testStr = new String("I LOVE YOU");
            os.write(testStr.getBytes());
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (os != null) {
                os.close();
            }
        }

总结

本文首先介绍了java.io 包中的重要接口和类,如InputStream接口,OutputStream接口,Reader接口和Writer接口。然后,通过几个小demo阐述了如何运用这些接口的实现类来操作文件。希望多读者朋友有所帮助。

源代码

https://github.com/XWxiaowei/JavaCode/tree/master/io-study-demo

相关文章
|
5月前
|
监控 Java API
现代 Java IO 高性能实践从原理到落地的高效实现路径与实战指南
本文深入解析现代Java高性能IO实践,涵盖异步非阻塞IO、操作系统优化、大文件处理、响应式网络编程与数据库访问,结合Netty、Reactor等技术落地高并发应用,助力构建高效可扩展的IO系统。
166 0
|
5月前
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
225 0
|
2月前
|
Java Unix Go
【Java】(8)Stream流、文件File相关操作,IO的含义与运用
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。!但本节讲述最基本的和流与 I/O 相关的功能。我们将通过一个个例子来学习这些功能。
194 1
|
5月前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
369 83
|
4月前
|
Java 测试技术 API
Java IO流(二):文件操作与NIO入门
本文详解Java NIO与传统IO的区别与优势,涵盖Path、Files类、Channel、Buffer、Selector等核心概念,深入讲解文件操作、目录遍历、NIO实战及性能优化技巧,适合处理大文件与高并发场景,助力高效IO编程与面试准备。
|
4月前
|
SQL Java 数据库连接
Java IO流(一):字节流与字符流基础
本文全面解析Java IO流,涵盖字节流、字符流及其使用场景,帮助开发者理解IO流分类与用途,掌握文件读写、编码转换、异常处理等核心技术,通过实战案例提升IO编程能力。
|
5月前
|
存储 Java Linux
操作系统层面视角下 Java IO 的演进路径及核心技术变革解析
本文从操作系统层面深入解析Java IO的演进历程,涵盖BIO、NIO、多路复用器及Netty等核心技术。分析各阶段IO模型的原理、优缺点及系统调用机制,探讨Java如何通过底层优化提升并发性能与数据处理效率,全面呈现IO技术的变革路径与发展趋势。
125 2
|
9月前
|
Java 数据库
【YashanDB知识库】kettle同步大表提示java内存溢出
在数据导入导出场景中,使用Kettle进行大表数据同步时出现“ERROR:could not create the java virtual machine!”问题,原因为Java内存溢出。解决方法包括:1) 编辑Spoon.bat增大JVM堆内存至2GB;2) 优化Kettle转换流程,如调整批量大小、精简步骤;3) 合理设置并行线程数(PARALLELISM参数)。此问题影响所有版本,需根据实际需求调整相关参数以避免内存不足。
|
9月前
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
376 23
|
10月前
|
安全 Java 开发者
Java并发迷宫:同步的魔法与死锁的诅咒
在Java并发编程中,合理使用同步机制可以确保线程安全,避免数据不一致的问题。然而,必须警惕死锁的出现,采取适当的预防措施。通过理解同步的原理和死锁的成因,并应用有效的设计和编码实践,可以构建出高效、健壮的多线程应用程序。
186 21