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负责把对象…

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

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

Android 多进程开发

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

clion中链接openssl库

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

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

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

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

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

Java提高篇 —— Java三大特性之继承

一、前言 在《Think in java》中有这样一句话:复用代码是Java众多引人注目的功能之一。但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情。在这句话中最引人注目的是“复用代码”,尽可能的复用代码…

Java提高篇 —— Java三大特性之多态

一、前言 面向对象编程有三大特性:封装、继承、多态。 封装:隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法。 继…

光盘刻录制作Ubuntu等操作系统的启动盘

前提条件 软媒刻录 空白光盘(至少4.7G)电脑(最好使用外置的光驱)系统镜像(ISO格式) 具体操作 打开软媒魔方选择光盘刻录按照标红的进行选择选择镜像->选择或者拖拽都可以选择刻录机->如果使用外部刻…

Java提高篇 —— String缓冲池

一、String缓冲池 首先我们要明确,String并不是基本数据类型,而是一个对象,并且是不可变的对象。查看源码就会发现String类为final型的(当然也不可被继承),而且通过查看JDK文档会发现几乎每一个修改String对…

Java基础 —— JVM内存模型与垃圾回收

目录一、概述二、运行时数据区方法区运行时常量池堆栈本地方法栈程序计数器三、对象访问四、垃圾回收如何定义垃圾1、引用计数法2、可达性分析垃圾回收方法1、Mark-Sweep标记-清除算法2、Copying复制算法3、Mark-Compact标记-整理算法4、Generational Collection 分代收集垃圾收…

Report Design

ERP_ENT_STD-CSDN博客

Java提高篇 ——Java注解

目录一、注解注解的定义注解的应用元注解RetentionDocumentedTargetInheritedRepeatable注解的属性Java 预置的注解DeprecatedOverrideSuppressWarningsSafeVarargsFunctionalInterface二、注解的提取三、注解与反射四、注解的使用场景五、亲手自定义注解完成某个目的六、注解应…

Android 性能优化四个方面总结

目录一、四个方面二、卡顿优化1、Android系统显示原理2、卡顿根本原因3、性能分析工具(1)Profile GPU Rendering(2)TraceView(3)Systrace UI 性能分析4、优化建议(1)布局优化&#x…

Android 开源框架选择

目录一、前言二、APP的整体架构三、技术选型的考量点四、日志记录能力五、JSON解析能力1、gson2、jackson3、Fastjson4、LoganSquare六、数据库操作能力1、ActiveAndroid2、ormlite3、greenDAO4、Realm七、网络通信能力1、android-async-http2、OkHttp3、Volley4、Retrofit八、…

Android Studio 自定义Gradle Plugin

一、简介 之前公司的一个项目需要用到Gradle插件来修改编译后的class文件,今天有时间就拿出来整理一下,学习一下Gradle插件的编写还是一件十分有意义的事。 二、Gradle插件类型 一种是直接在项目中的gradle文件里编写,这种方式的缺点是无法复…

Android Studio Gradle两种更新方式

第一种、Android Studio自动更新 第一步:修改gradle版本 修改项目根目录/gradle/wrapper/gradle-wrapper.properties最后一行的地址: distributionUrlhttps://services.gradle.org/distributions/gradle-3.3-all.zip新gradle地址从官方下载的地方有。…

Android Canvas的drawText()和文字居中方案

自定义View是绘制文本有三类方法: // 第一类 public void drawText (String text, float x, float y, Paint paint) public void drawText (String text, int start, int end, float x, float y, Paint paint) public void drawText (CharSequence text, int start…

IntelliJ IDEA配置Tomcat

查找该问题的童鞋我相信IntelliJ IDEA,Tomcat的下载,JDK等其他的配置都应该完成了,那我直接进入正题了。 1、新建一个项目 2、由于这里我们仅仅为了展示如何成功部署Tomcat,以及配置完成后成功运行一个jsp文件,我仅勾…