API的误解
最近被同事问到一个问题,就是他做的文件下载功能下载下来的结果不对,在review代码的时候,发现了如下的写法。
byte[] bytes = new byte[1024];
int len = 0;
while((len = in.read(bytes))>0){
os.write(bytes);
}
然后就把bytes写入文件了。然后最后数据多了,这个问题,主要是没有仔细看java的api。
public int read(byte[] b) throws IOException
read方法接受一个数组,并且返回一个int类型的长度,表示这次读取了多少数据。多出数据的原因就是没有获取到返回的长度进行合理的获取。
下面简单说一下不检验长度的问题。
byte[] b=new byte[5]第一次从读取文件返回返回以后被填满。
{1,2,3,4,5}
下次没有5个数据只有三个了
{6,7,8,4,5}
一直使用这个byte会发现,下次数据如果写入byte的全部的长度的话,就会有脏数据,{4,5}。这就是问题的原因,没有注意方法的返回值。
如果是一个正常的java文件拷贝,例如下面的代码
byte[] bytes = new byte[1024];
while ((i = bis.read(bytes)) >0 ) {
os.write(bytes, 0, i);
}
每次需要读取到返回值,然后写入的时候,然后把数组的值,按照长度截取传入。
最佳实践
java7的特性nio2–Files
static long copy(InputStream in, Path target, CopyOption... options)
static long copy(Path source, OutputStream out)
static Path copy(Path source, Path target, CopyOption... options)
在java7 nio的特性里,提供了丰富的拷贝的方式。底层都是通过jni实现的拷贝,要比java中写byte数组拷贝要更高效,减少了对象从堆内存到系统内存的折腾。
顺带说一下,nio2其他的比较好用的拷贝文件可能用到的方法。
static InputStream newInputStream(Path path, OpenOption... options)
static OutputStream newOutputStream(Path path, OpenOption... options)
用静态方法获取输入输出流。通过这个方法只是让代码更短,看着舒服。这个相当于静态工厂了。
static byte[] readAllBytes(Path path)
static List<String> readAllLines(Path path, Charset cs)
直接获取到文件所有数组以及所有行。这里不用再去考虑什么文件关闭的问题。比try-with-resource还简单。
static Path createFile(Path path, FileAttribute<?>... attrs)
static void delete(Path path)
static Path move(Path source, Path target, CopyOption... options)
普通的文件操作。
nio2带来了优势主要是在一些特殊功能上,一方面是有更高效的jni实现,一方面是静态方法使得调用的代码更整洁。
如果jdk在7以下。就需要考虑common io的封装的操作。性能上可能没有提升,但是也能使得调用代
common io
CopyUtils
Method Input Output Dependency
------ ----- ------ -------
1 copy InputStream OutputStream (primitive)
2 copy Reader Writer (primitive)
3 copy InputStream Writer 2
4 copy Reader OutputStream 2
5 copy String OutputStream 2
6 copy String Writer (trivial)
7 copy byte[] Writer 3
8 copy byte[] OutputStream (trivial)
common io有更多的封装,有InputStream到OutputStream的拷贝,这个可以直接应用到网络io。
common io关闭的方式需要注意
try {
return IOUtils.copy(inputStream, outputStream);
} finally {
IOUtils.closeQuietly(inputStream, outputStream);
}
总结
java7已经是提供了很强大的功能了,在不依赖其他库的时候是不错的选择。如果可以引用common io。建议可以考虑common io。因为他封装的更多,应对复杂的场景,可以写较少的代码。