字节流与缓冲流

java零基础入门-高级特性篇(十二) IO 流 2

本章先来看两大“流”派中的字节流。字节流相对字符流总体结构简单一点,只用记住它的4个最基本的操作类就可以了。下面一张图来看看这四个基本的操作类。

图解

上面这张图通过两个方面进行划分,一个是输入和输出,一个是具不具备缓冲功能。下面来具体分析一下。

不带缓冲的输入输出

FileInputStream

首先在磁盘上创建一个txt文件,我在D盘根目录创建(文件名为demo.txt),然后使用FileInputStream这个类来读取这个文件。

读取文件

这是最基本的文件读取方法。这段代码中有几个地方要注意一下。首先是File类型。这个也是处理文件的重要类型,下面先插个队,来先介绍一下File。

File

File用来操作文件,注意,这里是操作文件本身,而不是获得文件的内容,获取文件的内容就需要使用流了。比如上面的demo.txt文件,可以用File类通过文件在系统中的路径获取文件,但File无法读取demo.txt中的内容。通过文件路径创建File类型的对象以后,就可以通过一系列的API来操作文件,比如常用的一些方法:

getName():用于返回文件名或者路径。getPath():返回对象的路径。exists():判断文件是否存在等等。除了操作文件,还可以操作文件夹,比如mkdir()方法可以创建文件夹,经常和exists方法一起使用,判断是否需要创建文件夹,如果需要的文件夹不存在则创建它。

File类

以上代码就是File的基本操作,其他的操作可以参考API,这里不再逐一演示。总之,记住一点,File类型操作的是文件本身,无法操作文件内容

第二个要注意的是D:\\demo.txt这个路径。我们通常使用windows作为编码的系统,而windows中路径分隔符是单个 \ ,但是在java代码中,需要添加一个\作为转义符,这样才能被java识别为路径分隔符。注意,我这里强调了windows系统,因为好死不死,在linux里面的路径分隔符恰恰是反的 / 。由于我们的代码最终会放在服务器上运行,所以我们不能将路径写死成只有windows系统可以识别的 \\ 。我们需要一个在windows里是 \ ,在linux里是 / 的方法。

这个方法File类也帮我们做好了,就是File.separator,将上面的路径改造为平台无关的写法就是

"D:" + File.separator + "demo.txt"

平台无关的路径分隔符:意思就是无论哪个平台都可以获取正确的路径分隔符,在windows下File.separator是 \,在linux下File.separator是 / 。

好了,File的基本操作介绍完了,下面继续介绍流。使用File类型根据文件路径创建一个文件的对象,然后用这个对象作为FileInputStream输入流的构造器参数,创建一个输入流。这样就可以通过流来获取文件的内容了。上例中,通过while循环逐个字节的读取文件中的内容,然后转换为char类型进行输出。

来看一下FileInputStream的构造器。FileInputStream有两个我们常用的构造器,一个接受File类型参数,就是上例中的写法。还有一个构造器接受一个字符串的参数,也就是文件路径。

构造器

这里顺便复习一下this关键字,在构造器中的this表示调用这个类的另一个不同参数的构造器,来看看this后面括号表示的是什么意思。如果参数中的文件不为空,那么就根据参数地址创建一个匿名文件对象,然后调用下面这个参数为File类型的构造器,所以上例中可以省略掉File对象的创建,直接给流传递一个文件路径也是可以的,因为接受字符串的构造器也可以完成创建File类型对象的工作。

FileInputStream fis = new FileInputStream("D:\\demo.txt");

但是这种输出方式有缺点,上一章介绍过中文编码,由于中文数量过于庞大,所以根据编码表中的编码,一个汉字可能占用2个或者3个甚至4个字节,这样如果逐个字节输出的话,当需要输出的内容是中文的时候,就会出现乱码。因为可能只输出了二分之一个或者三分之一个中文,这样没法显示一个完整的中文,只能是乱码。所以如果需要输出一个正确的中文,需要对代码进行改造。

中文乱码

改造的话就不能再是逐个字节的输出,而是需要将多个字节放在一起,同时读出来。

无乱码

这样将多个字节内容,通过String的构造器将字节转换为字符串,就可以正确的输出中文了。

为什么不读取一个视频或者图片,而要读取一个文本文件?文本文件不是应该使用字符流吗?

因为这里使用文本文件方便演示,如果读取一个图片或者视频,Eclipse没有办法来展示读取的图片或者视频,所以用文本文件来做例子比较方便。

FileOutputStream

既然输入流是读取文件的内容,那么相对应的,输出流就是将内容写入到文件中。下面来看看如何将内容写入文件。

输出流

首先看代码,首先是系统无关的分隔符写法,这里没有使用 \\ 而是使用File.separator替代。另外,和输入流类似的,输出流也有字符串参数的构造器。在这个构造器中,也有将文件路径转为File对象的操作,所以这里没有创建File对象的过程。

与输入流对应的,输出流将字符转为对应的int,然后逐个将int使用输出流的write方法,写入到文件中。除了使用int类型写入文件,还可以使用字节写入文件,这里与输入流操作类似,就不在过多解释,各位可以参照上面输入流的方法和API自行完成。

还是给点提示吧,字符串转为字节,可以使用getBytes()方法完成。上例中不再需要循环逐个读入字符,而是将str转为字节,str.getBytes(),然后用输出流fos调用write方法的重载方法write(str.getBytes())即可。

具有缓冲功能的输入输出

介绍完两个最基本的输入输出流后,再来看看具有缓冲功能的流如何使用。在看代码之前,首先要弄清楚,什么是具有缓冲功能。

缓冲流

上面讲解的普通流是逐个字节进行输入或输出,这样虽然可以完成工作,但是在效率上有很大的问题。当我们将文件读取的时候,会先加载到内存,然而刚刚加载了一个字节到内存,马上又要告诉磁盘,喂~大兄弟,给我把这个字节写到磁盘上,我们知道磁盘的效率比内存要低很多的,在磁盘写入的过程中,内存只能干瞪眼,当磁盘写完一个字节后,内存再把下一个字节交给磁盘,喂~大兄弟,继续写下一个,然后内存又等着磁盘写下一个字节。

普通流效率低下的最大原因就在于此,频繁的调用磁盘,导致无法发挥内存速度快的优点。于是为了提高效率,缓冲流出现了。看看缓冲流缓冲了什么?缓冲流并不是每一个字节都要调用一次磁盘,而是根据设置的缓冲区大小,每当缓冲区满了以后,再调用一次磁盘,比如上图中,缓冲区设置为3,结果就是每次缓冲区有3个字节的数据以后,再调用一次磁盘,这样一来,调用磁盘的次数就减少了很多,使效率得到了很大的提升。文件越大,缓冲流效率的提升越明显。

下面来看一个例子,首先是普通流。

普通流的文件复制

这里的普通流没有设置缓冲区,逐个字节进行文件读入和写入,花了17秒完成5m文件的复制。这里要注意的是流是需要关闭的,如果不关闭流可能会出现资源被占用或者内存泄漏的问题,通常在finally中关闭流,避免导致没有执行到流的关闭就抛出异常导致关闭流不成功。

缓冲流的文件复制

使用缓冲流进行文件的复制,可以看到文件的复制效率提高了很多。缓冲流的创建,需要InputStream子类作为参数,除了将普通流外面包装了一层,其他代码与普通流没有区别,这种包一层就能有更强功能的流,还有个名称叫做高级流,这种包一层的做法,有种更优雅的名称---“装饰模式”。关于装饰模式,后面章节来具体说明。

缓冲流自带缓冲区,这个缓冲区多大?

部分源码

理解了普通流的用法,缓冲流用起来没有什么难度,它仅仅是包装了一层而已,所以当我们需要对磁盘上的文件进行读写操作的时候,建议使用缓冲流,效率要高很多。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容