关于FileOutputStream的异常

今日起兴搞搞文件与流的知识,刚起手写了个读取与生成文件的小程序,跑完以后,发现一张366kb的图像被代码给生生的写成了180kb大小的损坏文件?!我艹,这是几个意思?刚起手就被拍死了啊!
原始的代码:
FileInputStream in=null;
FileOutputStream out=null;
try {
in=new FileInputStream("C:\\Users\\Administrator\\Desktop\\promo\\20150417114.jpg");
out=new FileOutputStream("C:\\Users\\Administrator\\Desktop\\promo\\sub\\test.jpg");
while(in.read()!=-1){
out.write(in.read());
out.flush();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{

out.close();

in.close();
}
从逻辑上来看一点事都没有,可是在跑完了以后,与写之前设想的效果差的太远!本来就简短的代码,瞬间充满了陌生···,于是开始一句一句的推敲。首先关于输入和输出对象是没问题的,可以排除,继续,读取也是没有问题的,要不然也不会生成半拉莫名文件。问题于是就锁定在了write()方法上。查看outputstream的api,发现关于outputstream的write()方法的介绍很凝练,很简洁,就一句话,"将指定字节写入此文件输出流。"这是没问题的。不过后半句留下了线索,"实现outputstream的write方法"。好的,路没断就行,顺藤摸瓜,查看outputstream的write方法,"将指定的字节写入此输出流。write方法的常规协定是:向输出流写入一个字节。要写入的字节是参数b的八个低位。b的24个高位将被忽略。outputstream的子类必须提供此方法的实现"。也是很短的但是却很详细很关键的一句话,"b的24个高位将被忽略"。我了个大艹!问题已经很明确了,就是在文件传输过程中丢失了一些数据。是很明确了!可是这个高低位是个毛意思?还是不甚清楚啊。当然,其实,到了这,有两个选择,一是既然知道问题出现在哪里,就可以避免这个这个坑,就选择别的方法,不让数据丢失,另外一个就是去看看这丢失的数据到底是什么?有时候人的好奇心就是这么自然的出现的,很自觉的就去百度了,字节的高地位。看到很多不知道牛逼几何的人物的文章都说百度不咋滴,查资料都用谷歌什么的,我只想说你可以鄙视百度,但不能鄙视百度出来的结果。好的,结果出来了,话说有个叫字节序的名词,其含义很直白,就是字节的顺序。嗯,很白。通俗易懂到很通俗,嗯,懂了。不过更深的内涵就有点意思了,起码对于解决问题有了后续的线索。"大于一个字节类型的数据在内存中的存放顺序"。都说一入某某深似海,查资料也是这样,引出来的新名词又引出来新的名词,瞪着俩眼看吧,Big—Endia和little-Endia。Big-Endia,就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。Little-Endia,就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。我擦,有点晕,故事不到结束,那就还有剧情。且看着。网络字节序:4个字节的32bit值以一种神秘的次序传输,首先是0-7bit,然后8-15bit,再然后16-23bit,最后是24-31bit.嗯,很神奇。然后这种神奇的传输次序被有关行业称作大端字节序。到目前为止,对于解决问题我自认为还没什么进展。耐心,面对着急是脆弱的。跳一下看看···有时候吃坏东西拉肚子不是东西不能吃,而是我们的消化能力有问题。答案就在那里,偏偏看了还不懂,此时我懂了,为什么会有限制级这个名词了,因为有些东西可能看了也不懂。好的,心态调好了,就再换一份看,等到消化能力上去了,再看吧。看着看着,发现查出来的资料都不能解我心头之惑。反而牵扯出来新的东西开始在脑海里打转,查资料的解决方式到此应该打住了,不管新的问题有多大,都不能湮灭最初的起点。我只是想知道b的24个高位是啥玩意?我就是想知道我写出的文件为啥无辜的成了半拉?答案已经出来了,只是我看不懂而已。东西能吃,拉肚子只是我消化能力不行而已。为啥文件成了半拉?因为调用的方法将读入的数据在写出的时候丢了一部分。好的,勉强也算是完成了逻辑上的圆满。好,既然write方法会丢失数据,那么有没有别的方法解决问题呢?嗯,有的。除了write()方法不是还有write(byte[] b)吗?这么一改,用一个byte数组去接数据,果然就好了
byte[] b=new byte[1024];
while(in.read(b)!=-1){
out.write(b);
out.flush();
}
这又是什么情况?这到底是什么情况?查看outputstream的源码:
public void write(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);
}
}
write(byte[]b)和write(byte[] b, int off,int len)最后走的都是上边的方法。到了这里我突然很好奇我的in.read()方法到底读了些什么玩意儿?把in.read()打到控制台输出的是一大堆没有规律的数字,把in.read(b)打到控制台,是清一色的1024,哦,最后一个是683。这是几个意思?瞬间我感觉是这个read()方法出了问题同样的走到了顶层的InputStream里边的是个抽象方法,谁用谁重写。那就看Read(byte[]b)
public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}

int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;

int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
返回的是个int?返回的是i?返回的是个长度?那我刚才打出的read(byte[]b)的就是文件的size?我统计了一下,打出了366个1024。我晕了,懵了,愣了,傻了,蛋疼了···各种心酸各种苦涩,我读书少,我好怕,折腾了这么一大圈,我还是不能理解我那个183kb大小的文件到底是怎么出来的,而我更不能理解的是为什么换了个方法就可以输出正确?那个read(byte b[], int off, int len)方法里的for循环到底是有怎样的魔力?只不过是把读到的字节按顺序附加到了数组里而已。这尼玛?····哎,有点意思啊?根据打出的read()和Read(byte[]b)结果对比,好像有点启发,read()方法每次读取一个字节,read(byte[]b)每次读取b.length大小字节,不不不,read()方法读取的数据有问题,大大的有问题,我直接循环打出read()方法,竟然是无数个255,跑了三分钟也没停止。这个不是重点,重点是255,255,虽然不太清楚是什么含义,但是我就是认为它有问题,诬陷有罪,怀疑合理。我就是怀疑它有问题,嗯,有问题,图片的存储方式是什么的?read()读到的到底是什么玩意儿?!我使用的是jpg格式的图片,百度出来的东西让我开始疼,头疼,蛋疼,全身疼···,没事,没事,只要顺着线索总会有结束的真相。不对,255=2^8-1也就是一个字节?!哈哈,我找到了
FileInputStream in=null;
FileOutputStream out=null;
int a=0;
try {
in=new FileInputStream("C:\\Users\\Administrator\\Desktop\\promo\\20150417114.jpg");
out=new FileOutputStream("C:\\Users\\Administrator\\Desktop\\promo\\sub\\test.jpg");
while(in.available()>0){
out.write(in.read());
out.flush();
}
/* byte[] b=new byte[2048];
while(in.read(b)!=-1){
out.write(b);
out.flush();
}*/
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
System.out.println(a);
out.close();
in.close();
}
}
我把猜想跑了一遍,果然,结果是正确的!有时候,问题越研究越被复杂,其实,最初的问题,很简单。重新梳理一下,首先创建一个输入对象,然后按每次一字节读取
in=new FileInputStream("C:\\Users\\Administrator\\Desktop\\promo\\20150417114.jpg");
out=new FileOutputStream("C:\\Users\\Administrator\\Desktop\\promo\\sub\\test.jpg");
int c=0;
while((c=in.read())!=-1){
out.write(c);
out.flush();
}
这样是没问题的,按最最开始的代码跑的话,最后的图片只有183kb大小,问题就出在

while(in.read()!=-1){
out.write(in.read());
out.flush();
}
人最容易忽略的地方就是明明脑子里是这样想的,手却不是这样做的!仔细,看api,"从输入流中读取一个数据字节如果没有输入可用,则此方法将阻塞",下面还有一句,"返回:下一个数据字节;如果已达文件末尾,则返回-1",就是这样一句话,导致了图片的数据缺失!当条件in.read()!=-1,调用了一次read(),此时输入流是刚刚好对应的是图片的假设是第一个数据点,而写入到输出流时又调用了read()方法,此时数据已经是图片的第二个数据点了!所以整个程序跑完,图片就这样被一次少一个数据点,一次少一个的给无辜的裁剪了···为了验证猜想,
while(in.read()!=-1){
out.write(in.read());
out.flush();
}
这样跑完,生成的图片是183kb大小,
while(in.read()!=-1){
System.out.println(in.read());
out.write(in.read());
out.flush();
}
这样跑完,图片的大小成了122kb大小
while(in.read()!=-1){
System.out.println("===="+in.read());
System.out.println("---"+in.read());
out.write(in.read());
out.flush();
}
这样跑完,图片的大小成了92kb大小
while(in.read()!=-1){
System.out.println("=="+in.read());
System.out.println("--"+in.read());
System.out.println("-+-"+in.read());
out.write(in.read());
out.flush();
}
这样跑完,图片仅剩72kb大小,这不是搞了压缩,这是数据丢失!丢失!什么是真相?这就是真相!要说贱人是怎么犯贱的,我想他们都是很自然的把原本应该不自然的事情给做了出来,还做的洋洋得意,然后一个人贱贱的慨叹高处不胜寒,贱贱的慨叹独孤求败了···
int c=in.read();
while(c!=-1){
out.write(c);
out.flush();

刚把数据丢失的问题给解决我只是挪了一下read的位置,问题又来了,图片的size开始猛涨,像嚼了炫卖似的停不下了!一兆,两兆···我艹,这是几个意思?!在往控制台输出,255,又见255!无数个草泥马般的255蜂拥着奔袭控制台,停不下来!根本停不下来!这是好事,一部好的小说,挖了坑,埋了伏,就要有个交代,没错,这个255就是龙套的255=2^8-1,没错,就是它!话说有时候一个问题解决了,所有的问题就都不是问题了。如果我没猜错,这个255是图片的第一个数据点,而打出的无数个255全部都是第一个数据点,c=in.read();只读了一个字节,然后就开始进入了死循环···阿弥陀佛,至此,最初的问题,是已经解决了。可是,因果轮回,无意间种下的因,不知何时会结成孽果···什么是字节序?不是说b的24个高位将被忽略?图片的存储方式?唉,生命不息,折腾不止···

时间: 2024-10-22 10:17:33

关于FileOutputStream的异常的相关文章

FileOutputStream&amp;FileInputStream&amp;异常的使用

我们总觉得历史是极其遥远的东西,与我们并无关联,又觉得历史隐藏在图书馆的旧书之中. 然而,我们每个人都有真真切切的历史.那便是每日的历史.今天自己做了些什么,又是怎么做的,都会成为你历史中的一页. 是畏缩不前.碌碌无为,还是勇猛挑战,花心思比昨天做的更好.每种态度,都会写就属于你的历史. --尼采 <快乐的知识> 以下是今天的练习,这些是自己在看着官方说明文档写出来的练习: 1 package Zhang; 2 3 import java.io.File; 4 5 import java.io

try~Catch语句中异常的处理过程

[2014/10/12 21:40]文章待续~ 1.函数自身捕获处理异常的情况 下面的例子介绍了try~catch语句中出现异常时语句的执行顺序: package month10; import java.lang.*; public class TryCatch{ /* * 函数产生一个ArithmeticException异常 */ public static void First(){ System.out.println("第一个异常处理的例子"); try{ //double

RSA加密异常

在利用RSA进行数据加密时,出现如下异常: Exception in thread "main" javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes at com.sun.crypto.provider.RSACipher.a(DashoA13*..) at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA13*..) a

Java IO流(第三讲):字节流中的FileInputStream与FileoutputStream

一.概念 FileInputStream和FileOutputStream 是一对继承与InputStream和OutputStream的类,用于本地文件读写,按二进制格式读写并且顺序读写,读和写的文件流要区分开,即分别创建不同文件流对象. 二.记住in和out 死记硬背型: 不管你从磁盘读,从网络读,或者从键盘读,读到内存,就是InputStream. 不管你写入磁盘,写入网络,或者写到屏幕,都是OuputStream. 理解型: 有些人经常遇到InputStream.OuputStream,

从本地上传到hdfs上出现异常

hdfs dfs -put  从本地上传到hdfs上出现异常 与namenode  同台机器的datanode错误日志信息如下: 2015-12-03 09:54:03,083 WARN org.apache.hadoop.hdfs.server.datanode.DataNode: Slow BlockReceiver write data to disk cost:727ms (threshold=300ms) 2015-12-03 09:54:03,991 INFO org.apache.

Java基础知识强化99:Java 常见异常及趣味解释

常见 Java 异常解释:(译者注:非技术角度分析.阅读有风险,理解需谨慎:) 1. java.langjava.lang软件包是java语言的核心部分,它提供了java中的基础类. java.lang.Object,这是java.lang的根类,也是所有java类的超类. java.lang ArithmeticException 出现异常的运算条件时,抛出此异常.例如,一个整数"除以零" 你正在试图使用电脑解决一个自己解决不了的数学问题,请重新阅读你的算术表达式并再次尝试. Arr

JAVA学习--文件流FileInputStream和FileOutputStream操作

* 1.流的分类: * 按照数据流向的不同:输入流  输出流 * 按照处理数据的单位的不同:字节流  字符流(处理的文本文件) * 按照角色的不同:节点流(直接作用于文件的)  处理流 *  * 2.IO的体系 * 抽象基类            节点流(文件流)                                缓冲流(处理流的一种) * InputStream        FileInputStream            BufferedInputStream * Outp

记一则罕见的hive字段值异常引起map阶段的OOM

前段时间遇到了一个很诡异的发生的Map阶段的OOM异常,花了些时间才找到原因,这个简要记录一下. 先看log. 节点一的TaskTracker的log: 节点二的TaskTracker的log: 节点三的TaskTracker的log: 其他节点的TaskTracker中的log都和slave4的一样的: 故障分析: OOM是一个比较常见的故障,其中发生在reduce阶段最为常见,最有可能是数据通过map函数后,shuffle到reduce端处理时由于分布问题导致某个分组的值太多出现OOM.另外

路径名导致的异常:javax.imageio.IIOException: Can&#39;t read input file!

背景: 写了一个测试程序,目的是读取本地的图片,为其打上水印图片.在使用过程中总会遇到:javax.imageio.IIOException: Can't read input file!的错误,最开始以为是图片路径名称写的不对,按照网上的提示换成正斜线和反斜线都不行.后来发现问题的原因是:图片的路径中不能有点(英文点:.); 具体的错误异常提示如下: javax.imageio.IIOException: Can't read input file! at javax.imageio.Imag