11、java中的I/O流(1)

       我对于流的理解是这样的,计算机的本质本来就是对输入的数据进行操作,然后将结果输出的一种工具,数据在各个数据源节点之间进行流动,感觉流就是对这种状态的一种抽象,一个数据流表示的就是一系列数据序列,java存在现成的类库可以实现数据的主动获取和处理,这些操作数据的类库构成了java的I/O体系。

       流根据不同的方面可以分成不同的类型,根据流向可分为输入流和输出流;根据操作的数据单元不同可分为字节流(8bit)和字符流(16bit,Unicode编码)。

       在这里将流分成字节流和字符流来对java中相应的处理类做一下分类,I/O一般用于对在文件和网络之间流动的数据做处理,以处理以文件为载体的数据作为实例。

                                   

       介绍一下常用到的流,先说一下字节流,处理字节流的两个顶级抽象父类是处理输入流的InputStream和处理输出流的OutputStream。当处理文件时,可以使用他们的子类 FileInputStream 和 FileOutputStream,代码如下:

public class StreamTest {public static void main(String[] args) {StreamTest test = new StreamTest();
//		test.testFileInputStream();
//		test.testFileOutputStream();test.testCopyFile();}/*** 使用输入流读取文件中的信息,然后打印* @author chaizepeng**/public void testFileInputStream() {InputStream inputStream = null;File file = new File("E:\\test\\input.txt");try {inputStream = new FileInputStream(file);//将文件中的数据读入到输入流中byte[] b = new byte[1024];inputStream.read(b);//从输入流中读取1024个字节String s = new String(b, "utf-8");System.out.println(s);} catch (Exception e) {e.printStackTrace();}finally {//使用流操作非常耗资源,所以在使用完之后要及时关闭if (inputStream != null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}}/*** 使用输出流写出数据到文件中* @author chaizepeng**/public void testFileOutputStream() {File file = new File("E:\\test\\output.txt");OutputStream outputStream = null;try {outputStream = new FileOutputStream(file);//将数据流指向指定的文件String s = "hello world";byte[] bytes = s.getBytes("utf-8");outputStream.write(bytes);//将字节数组中的数据写入到输出流指向的文件中outputStream.flush();//刷新输出流,保证数据写入成功} catch (Exception e) {e.printStackTrace();}finally {//使用流操作非常耗资源,所以在使用完之后要及时关闭if (outputStream != null) {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}}/*** 将 E:\\test\\input.txt 复制到 E:\\test\\copy.txt* @author chaizepeng**/public void testCopyFile() {InputStream inputStream = null;OutputStream outputStream = null;File file = new File("E:\\test\\copy.txt");if (!file.exists()) {try {file.createNewFile();} catch (IOException e) {e.printStackTrace();}}try {inputStream = new FileInputStream("E:\\test\\input.txt");//将文件中的数据读入到输入流中//想往文件中追加信息时,使用另一个构造器即可:new FileOutputStream(file,true)outputStream = new FileOutputStream(file);//将输出流对准一个文件byte[] b = new byte[1024];int len = 0;while ((len = inputStream.read(b,0,b.length)) != -1) {//每次读取1024个字节outputStream.write(b,0,len);//将读取到的字节序列写入到输出流对应的文件中,知道输入流在文件中获取到的数据列长度为0}outputStream.flush();} catch (Exception e) {e.printStackTrace();}finally {//使用流操作非常耗资源,所以在使用完之后要及时关闭try {if (outputStream != null) {outputStream.close();}if (inputStream != null) {inputStream.close();} }catch (IOException e) {e.printStackTrace();}}}
}

想将数据从内存中读出并写入到另一块内存中时可以使用子类 ByteArrayInputStream 和 ByteArrayOutputStream ,代码如下:

public class ByteArrayStreamTest {public static void main(String[] args) {ByteArrayStreamTest test = new ByteArrayStreamTest();test.testByteArrayStream();}/*** 用于在内存中输入和输出,不必依赖磁盘,也就是不用创建File类* 因为处理的是内存中的数据,所以也不是非要关闭资源不可*/public void testByteArrayStream() {//ByteArrayInputStream 用于从内存中(不是在磁盘上)读入数据并创建一个输入流对象byte []b = "hello world".getBytes();ByteArrayInputStream inputStream = new ByteArrayInputStream(b);ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);byte []temp = new byte[4];//创建一个临时的数组,用于转移数据int len = 0;while ((len = inputStream.read(temp,0,temp.length) ) != -1) {outputStream.write(temp,0,len);//将内存中}System.out.println(outputStream.toString());//在输出流中获取写入到指定内存的数据}
}

        说一下字符流,例如:当处理一些中文文件时,使用字节流如果遇到突发事件可能会因为编码问题导致文件损坏,处理一些中文文件时可以选择字符流(处理文本文件时都可使用,为了不必要的麻烦,最好使用字节流),处理一些非文本文件时必须使用字节流。字符流的两个顶级接口是Reader和Writer,如果处理文件时可以使用FileReader和FileWriter,代码如下:

public class CharStreamTest {public static void main(String[] args) {CharStreamTest test = new CharStreamTest();test.testReaderTest();}/*** 将E:\\test\\reader.txt 复制到 E:\\test\\writer.txt **/public void testReaderTest() {FileWriter writer = null;FileReader reader = null;File file = new File("E:\\test\\writer.txt");if (!file.exists()) {try {file.createNewFile();} catch (IOException e) {e.printStackTrace();}}try {reader = new FileReader("E:\\test\\reader.txt");writer = new FileWriter(file);char []b = new char[1024];int len = 0;while((len = reader.read(b, 0, b.length)) != -1) {writer.write(b, 0, len);}writer.flush();} catch (IOException e) {e.printStackTrace();}finally {//使用流操作非常耗资源,所以在使用完之后要及时关闭try {if (writer != null) {writer.close();}if (reader != null) {reader.close();} }catch (IOException e) {e.printStackTrace();}}}}

        为了提高读入和写出的效率,java提供了缓冲流,使用缓冲流就相当于在内存中直接获取数据,而不需要频繁的去调用外部方法操作磁盘,大大提高了效率,缓冲流中维护了一个内存数组,每次读取数据时都在数组中获取,通过一定的机制当数组中没有数据或者数据已经读取完时就会调用一次应用的c或c++的方法操作一次磁盘,提高了效率。源码分析如下:

//通过源码来解释为什么缓冲流效率高//首先看一下不使用缓冲流//FileInputStream中的read方法,全都是最后调用native修饰的c或者c++的方法//也就是说当使用FileInputStream去读取数据时,每读取一次,都会去磁盘中获取一次数据//每次都去访问磁盘导致效率底public int read() throws IOException {return read0();}private native int read0() throws IOException;private native int readBytes(byte b[], int off, int len) throws IOException;public int read(byte b[]) throws IOException {return readBytes(b, 0, b.length);}public int read(byte b[], int off, int len) throws IOException {return readBytes(b, off, len);}//BufferedInputStream中的read方法,//创建缓冲流对象时,维护了一个数组,public BufferedInputStream(InputStream in, int size) {buf = new byte[size];}//调用的read方法public synchronized int read(byte b[], int off, int len){//删减一些代码,read中会调用read1方法int nread = read1(b, off + n, len - n);//在内存数组中获取数据,而不是去磁盘中获取,这也就是网上一直所说的不再是读一次获取一次,而是一次性读取多个放到内存中,大大节省了效率System.arraycopy(getBufIfOpen(), pos, b, off, cnt);}//调用的read1方法private int read1(byte[] b, int off, int len) throws IOException {//删减一些代码,read1中会调用InputStream中的read方法getInIfOpen().read(b, off, len);}//调用的read1方法getInIfOpenprivate InputStream getInIfOpen() throws IOException {//而返回的正好是构造缓冲流时传入的字节流in,所以说到底,最后直接去磁盘获取数据的还是应用的c/c++的代码,只不过一次获取固定大小长度的字节数据放到缓冲流类中维护的内存数组中InputStream input = in;if (input == null)throw new IOException("Stream closed");return input;}

针对字节流提供了BufferedInputStream 和 BufferedOutputStream 两个缓冲流,用法如下:

public class BufferStreamTest {public static void main(String[] args) {BufferStreamTest test = new BufferStreamTest();test.testInputBufferedStream();}public void testInputBufferedStream() {BufferedInputStream bufferedInputStream = null;BufferedOutputStream bufferedOutputStream = null;File file = new File("E:\\test\\bufferedoutput.ppt");try {bufferedInputStream = new BufferedInputStream(new FileInputStream("E:\\czp\\Learning Materials\\笔记\\io.ppt"));bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file));byte[] b = new byte[1024];int len;while((len = bufferedInputStream.read(b ,0 ,b.length)) != -1) {bufferedOutputStream.write(b, 0, len);}bufferedOutputStream.flush();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {if (bufferedOutputStream!=null) {bufferedOutputStream.close();}if (bufferedInputStream!=null) {bufferedInputStream.close();}} catch (Exception e2) {e2.printStackTrace();}}}
}

针对字符流提供了BufferedReader 和 BufferedWriter ,用法如下:

public class BufferStreamTest {public static void main(String[] args) {BufferStreamTest test = new BufferStreamTest();test.testBufferCharStream();}public void testBufferCharStream() {BufferedReader bufferedReader = null;BufferedWriter bufferedWriter = null;File file = new File("E:\\test\\bufferedreader.txt");try {FileReader reader = new FileReader("E:\\czp\\Learning Materials\\ceshi.txt");//BufferedReader 的数据源是一个字符输入流bufferedReader = new BufferedReader(reader);bufferedWriter = new BufferedWriter(new FileWriter(file));String s = "";while( (s = bufferedReader.readLine()) != null) {//每次读取一行数据System.out.println(s);bufferedWriter.write(s);bufferedWriter.newLine();//换行bufferedWriter.flush();//刷新缓冲区} } catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {//关闭资源try {if (bufferedWriter!=null) {bufferedWriter.close();}if (bufferedReader!=null) {bufferedReader.close();}} catch (Exception e2) {e2.printStackTrace();}}}
}

有的时候想用字符流进行数据的读写,但是呢,提供的只有数据的字节流,这时便可使用转换流,代码如下:

public class ConvertStreamTest {public static void main(String[] args) throws IOException {ConvertStreamTest test = new ConvertStreamTest();test.testInputStreamReader();test.testOutputStreamWriter();}/*** 字节输入流转换成字符输入流 */public void testInputStreamReader() throws IOException {FileInputStream fileInputStream = null;//字节输入流Reader inputStreamReader = null;//字符输入流try {//获取一个字节输入流fileInputStream = new FileInputStream("E:\\czp\\Learning Materials\\ceshi.txt");//通过转换输入流 InputStreamReader 的构造方法构造一个字符输入流inputStreamReader = new InputStreamReader(fileInputStream,"utf-8");char []ch = new char[2048];inputStreamReader.read(ch);//正常的在流中读取数据System.out.println(new String(ch));} catch (Exception e) {}finally {if (inputStreamReader!=null) {inputStreamReader.close();}if (fileInputStream!= null) {fileInputStream.close();}}}/*** 字节输出流转换成字符输出流 */public void testOutputStreamWriter() throws IOException {FileOutputStream fileOutputStream = null;Writer writer = null;try {fileOutputStream = new FileOutputStream("E:\\test\\bufferedreader.txt");writer = new OutputStreamWriter(fileOutputStream, "gbk");writer.write("测试转换流");} catch (Exception e) {}finally {if (writer != null) {writer.close();}if (fileOutputStream!=null) {fileOutputStream.close();}}}
}

 

使用java也可实现文件的压缩和解压缩,使用到的两个类是:GZIPInputStream、GZIPOutputStream,他们是util包下的类,不是io包下。代码如下:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;public class GZIPStreamTest {public static void main(String[] args) throws IOException {GZIPStreamTest test = new GZIPStreamTest();test.testZipStream();test.testUnZipStream();}/*** 压缩操作* 将E:\\czp\\Learning Materials\\ceshi.txt 压缩到 E:\\test\\a.zip*/public void testZipStream() throws IOException {FileInputStream fileInputStream = null;FileOutputStream fileOutputStream = null;GZIPOutputStream gzipOutputStream = null;File file = new File("E:\\test\\a.zip");try {fileInputStream = new FileInputStream("E:\\czp\\Learning Materials\\ceshi.txt");fileOutputStream = new FileOutputStream(file);gzipOutputStream = new GZIPOutputStream(fileOutputStream);byte []by = new byte[1024];int len = 0;while((len = fileInputStream.read(by, 0, by.length)) != -1) {gzipOutputStream.write(by, 0, len);gzipOutputStream.flush();}} catch (Exception e) {}finally {if (gzipOutputStream != null) {gzipOutputStream.close();}if (fileOutputStream != null) {fileOutputStream.close();}if (fileInputStream != null) {fileInputStream.close();}}}/*** 解压操作*/public void testUnZipStream() throws IOException {FileInputStream fileInputStream = null;FileOutputStream fileOutputStream = null;GZIPInputStream gzipInputStream = null;File file = new File("E:\\test\\b.txt");try {fileInputStream = new FileInputStream("E:\\test\\a.zip");gzipInputStream = new GZIPInputStream(fileInputStream);fileOutputStream = new FileOutputStream(file);byte []by = new byte[1024];int len = 0;while((len = gzipInputStream.read(by, 0, by.length)) != -1) {fileOutputStream.write(by, 0, len);fileOutputStream.flush();}} catch (Exception e) {}finally {if (fileOutputStream != null) {fileOutputStream.close();}if (gzipInputStream != null) {gzipInputStream.close();}if (fileInputStream != null) {fileInputStream.close();}}}
}

以上只是对java中I/O体系中常用的几个类做了简单的介绍,真正用的时候可以参考API。

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

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

相关文章

ASP.NET Core 集成测试

集成测试集成测试,也叫组装测试或联合测试。在单元测试的基础上,将所有模块按照设计要求(如根据结构图)组装成为子系统或系统,进行集成测试。实践表明,一些模块虽然能够单独地工作,但并不能保证…

使用C#开发Android应用之WebApp

近段时间了解了一下VS2017开发安卓应用的一些技术,特地把C#开发WebApp的一些过程记录下来,欢迎大家一起指教、讨论,废话少说,是时候开始表演真正的技术了。。1、新建空白Android应用2、拖一个WebView控件进来3、打开模拟器Genymot…

ASP.NET Core依赖注入深入讨论

这篇文章我们来深入探讨ASP.NET Core、MVC Core中的依赖注入,我们将示范几乎所有可能的操作把依赖项注入到组件中。依赖注入是ASP.NET Core的核心,它能让您应用程序中的组件增强可测试性,还使您的组件只依赖于能够提供所需服务的某些组件。举…

使用静态基类方案让 ASP.NET Core 实现遵循 HATEOAS Restful Web API

Hypermedia As The Engine Of Application State (HATEOAS)HATEOAS(Hypermedia as the engine of application state)是 REST 架构风格中最复杂的约束,也是构建成熟 REST 服务的核心。它的重要性在于打破了客户端和服务器之间严格的契约&…

【招聘(北京)】.NETCORE开发工程师(微服务方向)

组织:华汽集团北京研发中心位置:北京市朝阳区焦奥中心官网:www.sinoauto.com邮箱:taoxu.weisinoauto.com 项目:打造面向国内汽车后市场用户的一站式云服务平台(华汽云),形态包括B2B、…

确保线程安全下使用Queue的Enqueue和Dequeue

场景是这样,假设有一台设备会触发类型为Alarm的告警信号,并把信号添加到一个Queue结构中,每隔一段时间这个Queue会被遍历检查,其中的每个Alarm都会调用一个相应的处理方法。问题在于,检查机制是基于多线程的&#xff0…

编写一个Java程序,其中包含三个线程: 厨师(Chef)、服务员(Waiter)和顾客(Customer)

编写一个Java程序,其中包含三个线程: 厨师(Chef)、服务员(Waiter)和顾客(Customer)。他们的行动如下: 厨师准备菜肴,每次准备一个。服务员等待菜肴准备好,然后将其送到顾客那里。顾客等待服务员送来菜看后才开始吃。所有三个角色应该循环进行…

Hangfire使用ApplicationInsigts监控

起因我司目前使用清真的ApplicationInsights来做程序级监控。(ApplicationInsights相关文档: https://azure.microsoft.com/zh-cn/services/application-insights/ )其实一切都蛮好的,但是我们基于Hangfire的Job系统却无法被Ai所监控到&#…

NET主流ORM框架分析

接上文我们测试了各个ORM框架的性能,大家可以很直观的看到各个ORM框架与原生的ADO.NET在境删改查的性能差异。这里和大家分享下我对ORM框架的理解及一些使用经验。ORM框架工作原理所有的ORM框架的工作原理都离不开下面这张图,只是每个框架的实现程度不同…

20、java中的类加载机制

1、类加载机制是什么? 类加载机制指的就是jvm将类的信息动态添加到内存并使用的一种机制。 2、那么类加载的具体流程是什么呢? 一般说类加载只有三步:加载、连接和初始化,其中连接包括验证、准备和解析,用于将运行时加…

【北京】BXUG第12期活动基于 .NET Core构建微服务和Xamarin

分享主题:基于 .NET Core构建微服务实战分享分享者:薛锋 北京切尔思科技架构师 兼任东北大学信息安全工程师和技术主播,行业内专注于研究 .NET Core和Web应用,具有比较扎实的技术基础和数年的从业经历。在GitHub上主持数个开…

谈谈ASP.NET Core中的ResponseCaching

前言前面的博客谈的大多数都是针对数据的缓存,今天我们来换换口味。来谈谈在ASP.NET Core中的ResponseCaching,与ResponseCaching关联密切的也就是常说的HTTP缓存。在阅读本文内容之前,默认各位有HTTP缓存相关的基础,主要是Cache-…

使用 dynamic 类型让 ASP.NET Core 实现 HATEOAS 结构的 RESTful API

上一篇写的是使用静态基类方法的实现步骤: 使用dynamic (ExpandoObject)的好处就是可以动态组建返回类型, 之前使用的是ViewModel, 如果想返回结果的话, 肯定需要把ViewModel所有的属性都返回, 如果属性比较多, 就有可能造成性能和灵活性等问题. 而使用ExpandoObject(dynamic)就…

使用 BenchmarkDotnet 测试代码性能

先来点题外话,清明节前把工作辞了(去 tm 的垃圾团队,各种拉帮结派、勾心斗角)。这次找工作就得慢慢找了,不能急了,希望能找到个好团队,好岗位吧。顺便这段时间也算是比较闲,也能学习…

2017西安交大ACM小学期数论 [阅兵式]

阅兵式 发布时间: 2017年6月25日 12:53 最后更新: 2017年7月3日 09:27 时间限制: 1000ms 内存限制: 128M 描述 阅兵式上,将士们排成一个整齐的方阵,每个将士面朝前方。问正中心的将士能向前看到几个将士?注意,一条直线上的将…

28、jdbc操作数据库(5)

介绍一个稍微封装了jdbc的工具类org.apache.commons.dbutils,使用dbutils可以简化对数据库操作程序的开发。 API介绍 接下来通过实例的方式说一下dbutils的具体使用 添加jar包:commons-dbutils-1.7.jar 增、删、改 进行增、删、改操作,在…

2017西安交大ACM小学期数论 [等差数列]

等差数列 发布时间: 2017年6月25日 13:42 最后更新: 2017年7月3日 09:27 时间限制: 1000ms 内存限制: 128M 描述 给定正整数n,试问存在多少个和为n的等差数列? 当然,等差数列中每一项要为非负整数,且不考虑降序的等差数列。…

上古时期(大雾)的数据结构pdf

分块点分治Treap byWYCby\ WYCby WYC Part1 分块 概念 就是将nnn个数分成若干个块,然后要处理的时候整块一起的加上局部的直接暴力。 如果将块的大小分配好一般每次都是O(n)O(\sqrt n)O(n​)的。 而且因为十分暴力,所以有很多优秀的性质。 实现方法 …

33、JAVA_WEB开发基础之会话机制

会话是什么 一个客户端浏览器与web服务器之间连续发生的一系列请求和响应过程就是会话,这些过程中产生的一系列信息就是会话信息,会话机制就是用于维护这些信息一致性的一种技术。通俗的说就是,一个A账号访问服务器,进行多次交互…

35、JAVA_WEB开发基础之过滤器

是什么 过滤器javaweb的一个重要组件,一种规范,可以对发送到serlvet的请求进行拦截和响应进行过滤。实际开发中可以使用过滤器来对访问服务器的请求进行过滤,以提高安全性 过滤器的原理 可以配置过滤器对指定的请求进行过滤,就…