Java基础——Java IO详解

一、概述


1、Java IO

       Java IO即Java 输入输出系统。不管我们编写何种应用,都难免和各种输入输出相关的媒介打交道,其实和媒介进行IO的过程是十分复杂的,这要考虑的因素特别多,比如我们要考虑和哪种媒介进行IO(文件、控制台、网络),我们还要考虑具体和它们的通信方式(顺序、随机、二进制、按字符、按字、按行等等)。Java类库的设计者通过设计大量的类来攻克这些难题,这些类就位于java.io包中。

       在JDK1.4之后,为了提高Java IO的效率,Java又提供了一套新的IO,Java New IO简称Java NIO。它在标准java代码中提供了高速的面向块的IO操作。本篇文章重点介绍Java IO,关于Java NIO请参考我的另两篇文章:

Java NIO详解(一) 
Java NIO详解(二)


2、流

       在Java IO中,流是一个核心的概念。流从概念上来说是一个连续的数据流。你既可以从流中读取数据,也可以往流中写数据。流与数据源或者数据流向的媒介相关联。在Java IO中流既可以是字节流(以字节为单位进行读写),也可以是字符流(以字符为单位进行读写)。


3、IO相关的媒介

Java的IO包主要关注的是从原始数据源的读取以及输出原始数据到目标媒介。以下是最典型的数据源和目标媒介:

  • 文件
  • 管道
  • 网络连接
  • 内存缓存
  • System.in, System.out, System.error(注:Java标准输入、输出、错误输出)


二、Java IO类库的框架


1、Java IO的类型

虽然java IO类库庞大,但总体来说其框架还是很清楚的。从是读媒介还是写媒介的维度看,Java IO可以分为:

       1)输入流:InputStream和Reader

       2)输出流:OutputStream和Writer


而从其处理流的类型的维度上看,Java IO又可以分为:

       1)字节流:InputStream和OutputStream

       2)字符流:Reader和Writer


下面这幅图就清晰的描述了JavaIO的分类:

  字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer


       我们的程序需要通过InputStream或Reader从数据源读取数据,然后用OutputStream或者Writer将数据写入到目标媒介中。其中,InputStream和Reader与数据源相关联,OutputStream和writer与目标媒介相关联。 以下的图说明了这一点:



2、IO类库
       上面我们介绍了Java IO中的四各类:InputStream、OutputStream、Reader、Writer,其实在我们的实际应用中,我们用到的一般是它们的子类,之所以设计这么多子类,目的就是让每一个类都负责不同的功能,以方便我们开发各种应用。各类用途汇总如下:

  • 文件访问
  • 网络访问
  • 内存缓存访问
  • 线程内部通信(管道)
  • 缓冲
  • 过滤
  • 解析
  • 读写文本 (Readers / Writers)
  • 读写基本类型数据 (long, int etc.)
  • 读写对象

下面我们就通过两张图来大体了解一下这些类的继承关系及其作用

图1:java io 类的集成关系



图2:java io中各个类所负责的媒介



三、Java IO的基本用法


1、Java IO:字节流

       通过上面的介绍我们已经知道,字节流对应的类应该是InputStreamOutputStream,而在我们实际开发中,我们应该根据不同的媒介类型选用相应的子类来处理。下面我们就用字节流来操作文件媒介:

例1,用字节流写文件

  public static void writeByteToFile() throws IOException{String hello= new String( "hello word!");byte[] byteArray= hello.getBytes();File file= new File( "d:/test.txt");//因为是用字节流来写媒介,所以对应的是OutputStream //又因为媒介对象是文件,所以用到子类是FileOutputStreamOutputStream os= new FileOutputStream( file);os.write( byteArray);os.close();}
例2,用字节流读文件

  public static void readByteFromFile() throws IOException{File file= new File( "d:/test.txt");byte[] byteArray= new byte[( int) file.length()];//因为是用字节流来读媒介,所以对应的是InputStream//又因为媒介对象是文件,所以用到子类是FileInputStreamInputStream is= new FileInputStream( file);int size= is.read( byteArray);System. out.println( "大小:"+size +";内容:" +new String(byteArray));is.close();}


2、Java IO:字符流

       同样,字符流对应的类应该是ReaderWriter。下面我们就用字符流来操作文件媒介:

例3,用字符流读文件

  public static void writeCharToFile() throws IOException{String hello= new String( "hello word!");File file= new File( "d:/test.txt");//因为是用字符流来读媒介,所以对应的是Writer,又因为媒介对象是文件,所以用到子类是FileWriterWriter os= new FileWriter( file);os.write( hello);os.close();}

例4,用字符流写文件

  public static void readCharFromFile() throws IOException{File file= new File( "d:/test.txt");//因为是用字符流来读媒介,所以对应的是Reader//又因为媒介对象是文件,所以用到子类是FileReaderReader reader= new FileReader( file);char [] byteArray= new char[( int) file.length()];int size= reader.read( byteArray);System. out.println( "大小:"+size +";内容:" +new String(byteArray));reader.close();}


3、Java IO :字节流转换为字符流
       字节流可以转换成字符流,java.io包中提供的 InputStreamReader类就可以实现,当然从其命名上就可以看出它的作用。其实这涉及到另一个概念,IO流的 组合,后面我们详细介绍。下面看一个简单的例子:

例5 ,字节流转换为字符流

  public static void convertByteToChar() throws IOException{File file= new File( "d:/test.txt");//获得一个字节流InputStream is= new FileInputStream( file);//把字节流转换为字符流,其实就是把字符流和字节流组合的结果。Reader reader= new InputStreamReader( is);char [] byteArray= new char[( int) file.length()];int size= reader.read( byteArray);System. out.println( "大小:"+size +";内容:" +new String(byteArray));is.close();reader.close();}


4、Java IO :IO类的组合

       从上面字节流转换成字符流的例子中我们知道了IO流之间可以组合(或称嵌套),其实组合的目的很简单,就是把多种类的特性融合在一起以实现更多的功能。组合使用的方式很简单,通过把一个流放入另一个流的构造器中即可实现,两个流之间可以组合,三个或者更多流之间也可组合到一起。当然,并不是任意流之间都可以组合。关于组合就不过多介绍了,后面的例子中有很多都用到了组合,大家好好体会即可。


5、Java IO:文件媒介操作

       File是Java IO中最常用的读写媒介,那么我们在这里就对文件再做进一步介绍。


1)File媒介

例6 ,File操作

public class FileDemo {public static void main(String[] args) {//检查文件是否存在File file = new File( "d:/test.txt");boolean fileExists = file.exists();System. out.println( fileExists);//创建文件目录,若父目录不存在则返回falseFile file2 = new File( "d:/fatherDir/subDir");boolean dirCreated = file2.mkdir();System. out.println( dirCreated);//创建文件目录,若父目录不存则连同父目录一起创建File file3 = new File( "d:/fatherDir/subDir2");boolean dirCreated2 = file3.mkdirs();System. out.println( dirCreated2);File file4= new File( "d:/test.txt");//判断长度long length = file4.length();//重命名文件boolean isRenamed = file4.renameTo( new File("d:/test2.txt"));//删除文件boolean isDeleted = file4.delete();File file5= new File( "d:/fatherDir/subDir");//是否是目录boolean isDirectory = file5.isDirectory();//列出文件名String[] fileNames = file5.list();//列出目录File[]   files = file4.listFiles();}
}


2)随机读取File文件
       通过上面的例子我们已经知道,我们可以用FileInputStream(文件字符流)或FileReader(文件字节流)来读文件,这两个类可以让我们分别以字符和字节的方式来读取文件内容,但是它们都有一个不足之处,就是只能从文件头开始读,然后读到文件结束。

       但是有时候我们只希望读取文件的一部分,或者是说随机的读取文件,那么我们就可以利用RandomAccessFile。RandomAccessFile提供了seek()方法,用来定位将要读写文件的指针位置,我们也可以通过调用getFilePointer()方法来获取当前指针的位置,具体看下面的例子:

例7,随机读取文件

  public static void randomAccessFileRead() throws IOException {// 创建一个RandomAccessFile对象RandomAccessFile file = new RandomAccessFile( "d:/test.txt", "rw");// 通过seek方法来移动读写位置的指针file.seek(10);// 获取当前指针long pointerBegin = file.getFilePointer();// 从当前指针开始读byte[] contents = new byte[1024];file.read( contents);long pointerEnd = file.getFilePointer();System. out.println( "pointerBegin:" + pointerBegin + "\n" + "pointerEnd:" + pointerEnd + "\n" + new String(contents));file.close();}


例8,随机写入文件

  public static void randomAccessFileWrite() throws IOException {// 创建一个RandomAccessFile对象RandomAccessFile file = new RandomAccessFile( "d:/test.txt", "rw");// 通过seek方法来移动读写位置的指针file.seek(10);// 获取当前指针long pointerBegin = file.getFilePointer();// 从当前指针位置开始写file.write( "HELLO WORD".getBytes());long pointerEnd = file.getFilePointer();System. out.println( "pointerBegin:" + pointerBegin + "\n" + "pointerEnd:" + pointerEnd + "\n" );file.close();}


6、Java IO:管道媒介

       管道主要用来实现同一个虚拟机中的两个线程进行交流。因此,一个管道既可以作为数据源媒介也可作为目标媒介。
       需要注意的是java中的管道和Unix/Linux中的管道含义并不一样,在Unix/Linux中管道可以作为两个位于不同空间进程通信的媒介,而在java中,管道只能为同一个JVM进程中的不同线程进行通信。和管道相关的IO类为: PipedInputStreamPipedOutputStream,下面我们来看一个例子:

例9,读写管道

public class PipeExample {public static void main(String[] args) throws IOException {final PipedOutputStream output = new PipedOutputStream();final PipedInputStream  input  = new PipedInputStream(output);Thread thread1 = new Thread( new Runnable() {@Overridepublic void run() {try {output.write( "Hello world, pipe!".getBytes());} catch (IOException e) {}}});Thread thread2 = new Thread( new Runnable() {@Overridepublic void run() {try {int data = input.read();while( data != -1){System. out.print(( char) data);data = input.read();}} catch (IOException e) {} finally{try {input.close();} catch (IOException e) {e.printStackTrace();}}}});thread1.start();thread2.start();}
}


7、Java IO:网络媒介

       关于Java IO面向网络媒介的操作即Java 网络编程,其核心是Socket,同磁盘操作一样,java网络编程对应着两套API,即Java IO和Java NIO,关于这部分我会准备专门的文章进行介绍。


8、Java IO:BufferedInputStream和BufferedOutputStream

       BufferedInputStream顾名思义,就是在对流进行写入时提供一个buffer来提高IO效率。在进行磁盘或网络IO时,原始的InputStream对数据读取的过程都是一个字节一个字节操作的,而BufferedInputStream在其内部提供了一个buffer,在读数据时,会一次读取一大块数据到buffer中,这样比单字节的操作效率要高的多,特别是进程磁盘IO和对大量数据进行读写的时候。

       使用BufferedInputStream十分简单,只要把普通的输入流和BufferedInputStream组合到一起即可。我们把上面的例2改造成用BufferedInputStream进行读文件,请看下面例子:

例10 ,用缓冲流读文件

public static void readByBufferedInputStream() throws IOException {File file = new File( "d:/test.txt");byte[] byteArray = new byte[( int) file.length()];//可以在构造参数中传入buffer大小InputStream is = new BufferedInputStream( new FileInputStream(file),2*1024);int size = is.read( byteArray);System. out.println( "大小:" + size + ";内容:" + new String(byteArray));is.close();
}

       关于如何设置buffer的大小,我们应根据我们的硬件状况来确定。对于磁盘IO来说,如果硬盘每次读取4KB大小的文件块,那么我们最好设置成这个大小的整数倍。因为磁盘对于顺序读的效率是特别高的,所以如果buffer再设置的大写可能会带来更好的效率,比如设置成4*4KB或8*4KB。
       还需要注意一点的就是磁盘本身就会有缓存,在这种情况下,BufferedInputStream会一次读取磁盘缓存大小的数据,而不是分多次的去读。所以要想得到一个最优的buffer值,我们必须得知道磁盘每次读的块大小和其缓存大小,然后根据多次试验的结果来得到最佳的buffer大小。

       BufferedOutputStream的情况和BufferedInputStream一致,在这里就不多做描述了。


9、Java IO:BufferedReader和BufferedWriter

       BufferedReader、BufferedWriter 的作用基本和BufferedInputStream、BufferedOutputStream一致,具体用法和原理都差不多 ,只不过一个是面向字符流一个是面向字节流。同样,我们将改造字符流中的例4,给其加上buffer功能,看例子:

public static void readByBufferedReader() throws IOException {File file = new File( "d:/test.txt");// 在字符流基础上用buffer流包装,也可以指定buffer的大小Reader reader = new BufferedReader( new FileReader(file),2*1024);char[] byteArray = new char[( int) file.length()];int size = reader.read( byteArray);System. out.println( "大小:" + size + ";内容:" + new String(byteArray));reader.close();
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/446981.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java基础——Java NIO详解(二)

一、简介 在我的上一篇文章Java NIO详解(一)中介绍了关于标准输入输出NIO相关知识, 本篇将重点介绍基于网络编程NIO(异步IO)。 二、异步IO 异步 I/O 是一种没有阻塞地读写数据的方法。通常,在代码进行 rea…

Java基础——Java NIO详解(一)

一、基本概念 1、I/0简介 I/O即输入输出,是计算机与外界世界的一个借口。IO操作的实际主题是操作系统。在java编程中,一般使用流的方式来处理IO,所有的IO都被视作是单个字节的移动,通过stream对象一次移动一个字节。流IO负责把对象…

MAC上Git安装与GitHub基本使用

参考链接 MAC上Git安装与GitHub基本使用

Java基础——深入理解Java线程池

简介 我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,…

密码机项目安装软件时候出现的问题以及对应的解决办法

Could NOT find Boost (missing: locale) (found version "1.65.1") 使用命令 apt-get install libboost-locale-dev 进行安装 解决普通用户cmake版本11,而root用户版本15,clion对于版本兼容的问题 修改clion里面的toolchain,将其…

Java基础——线程及并发机制

前言 在Java中,线程是一个很关键的名词,也是很高频使用的一种资源。那么它的概念是什么呢,是如何定义的,用法又有哪些呢?为何说Android里只有一个主线程呢,什么是工作线程呢。线程又存在并发,并…

密码机 密钥管理项目安装配置 从零开始

安装gcc 更新sudo apt-get update下载gcc sudo apt-get install gcc参考链接 不推荐 安装g 下载g sudo apt-get install g 安装make sudo apt -get install make参考链接 安装cmake 下载地址参考链接 安装ssh sudo apt-get install ssh 安装git和配置 sudo apt-get inst…

Androud 如何有效减少重复代码

前言 重复的代码一直都是可维护性的大敌,重构的重要任务之一也就是要去除掉重复的代码,有效的减少重复代码,可以大大提高软件的扩展性。 在Android开发中,很容易产生重复的代码。因为Android是组件,模板式开发&#xf…

解决在sample文件夹里面写代码,在测试的时候因为virtual原因,make编译报错

代码的结构 错误显示 解决办法 添加一句话,具体的cpp依据情况而定set_source_files_properties(${PROJECT_SOURCE_DIR}/src/sample_storage_test.cpp COMPILE_FLAGS "-Wno-unused-parameter")

Android SharedPreferences总结及优化

一、SharedPreferences简介 Android 中的 SharedPreferences(后续简称SP)是轻量级的数据存储方式,能够保存简单的数据类型,比如 String、int、boolean 值等。应用场合主要是数据比较少的配置信息。其内部是以 XML 结构保存在 /dat…

Java基础——深入理解ReentrantLock

一、简介在Java中通常实现锁有两种方式,一种是synchronized关键字,另一种是Lock。二者其实并没有什么必然联系,但是各有各的特点,在使用中可以进行取舍的使用。二、ReentrantLock与synchronized的比较相同点: &#xf…

使用开源的openssl的md5头文件,实现对于文件的md5代码

需要安装openssl的库 sudo apt-get install opensslsudo apt-get install libssl-dev参考链接 代码 #include "openssl/md5.h" #include <iostream> #include <fstream> #include <iomanip>//#define MAX_DATA_BUFF 1024; //#define MD5_LENGTH…

Android 多进程开发

前言正常情况下&#xff0c;一个apk启动后只会运行在一个进程中&#xff0c;其进程名为AndroidManifest.xml文件中指定的应用包名&#xff0c;所有的基本组件都会在这个进程中运行。但是如果需要将某些组件&#xff08;如Service、Activity等&#xff09;运行在单独的进程中&am…

clion中链接openssl库

错误显示 前提条件 apt-get install opensslapt-get install openssl-dev 解决办法 在CMakeLists.txt文件中加入如下命令link_libraries(crypto) 参考链接 无法将openssl库链接到CLion C 程序c - 无法将openssl库链接到CLion C程序

Java中String、StringBuffer、StringBuilder三者的区别

一、简介String、StringBuffer、StringBuilder三个类之间的区别主要是在两个方面&#xff1a;运行速度和线程安全。二、区别1、运行速度&#xff0c;或者说是执行速度在这方面运行速度快慢为&#xff1a;StringBuilder > StringBuffer > String StringString为字符串常量…

Ubuntu环境下,使用clion编译器,使用开源opensll的对称AES算法对于文件进行加密,C++代码

前提准备条件 需要安装openssl需要安装openssl-dev需要配置CMakeLists.txt文件集体内容可以参考我提供的相关参考链接 AES_file.h #include <openssl/aes.h> #include <iostream> #include <fstream> #include <cstring>#define RELEASE_ARRAY(P) if…

Java提高篇 —— Java关键字之static的四种用法

一、前言 在java的关键字中&#xff0c;static和final是两个我们必须掌握的关键字。不同于其他关键字&#xff0c;他们都有多种用法&#xff0c;而且在一定环境下使用&#xff0c;可以提高程序的运行性能&#xff0c;优化程序的结构。下面我们先来了解一下static关键字及其用法…

C++ 使用move来删除用户指定的文件

代码 #include <iostream>bool remove_file(std::string path){if (remove(path.c_str())0){std::cout << "success!" << std::endl;}else{std::cout << "False!" << std::endl;} } int main() {std::string path "/…

Java提高篇 —— Java关键字之final的几种用法

一、前言 在java的关键字中&#xff0c;static和final是两个我们必须掌握的关键字。不同于其他关键字&#xff0c;他们都有多种用法&#xff0c;而且在一定环境下使用&#xff0c;可以提高程序的运行性能&#xff0c;优化程序的结构。下面我们来了解一下final关键字及其用法。 …