某位刚来不久的实习生,在写一个File文件转Base64编码的项目过程中,需要关闭IO流,看他代码实在太长,就给了工具类,这篇幅里有讲,详见链接:https://blog.csdn.net/weixin_39309402/article/details/101447275
结果他执行代码的时候,发现文件内容为Null,就问我为什么?我先把代码贴上:
public class Base64ToString {
/**
*
* @param path
* @return String
* @description 将文件转base64字符串
*/
public static String fileToBase64(String path) {
String base64 = null;
InputStream in = null;
try {
File file = new File(path);
in = new FileInputStream(file);
byte[] bytes = new byte[(int) file.length()];
in.read(bytes);
base64 = Base64.getEncoder().encodeToString(bytes);
} catch (Exception e) {
System.out.println("" + e.getMessage());
} finally {
IOCloseUtil.close(in);
}
return base64;
}
/**
*
* @param destPath
* 存储路径
* @param fileName
* 存储文件名
* @param String
* Base64编码字符串
* @description BASE64解码成File文件
*/
public static void base64ToFile(String destPath, String base64, String fileName) {
File file = null;
File dir = new File(destPath);
if (!dir.exists() && !dir.isDirectory()) {
dir.mkdirs();
}
BufferedOutputStream bos = null;
java.io.FileOutputStream fos = null;
try {
byte[] bytes = Base64.getDecoder().decode(base64);
file = new File(destPath + File.separator + fileName);
fos = new java.io.FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bos.write(bytes);
} catch (Exception e) {
System.out.println("" + e.getMessage());
} finally {
IOCloseUtil.close(fos, bos);
}
}
public static void main(String[] args) {
// String base64Str = fileToBase64("H:\\Music\\123.txt");
// System.err.println(base64Str);
base64ToFile("H:\\Music", "5Z2a5oyB5piv5pmu6YCa5Lq66YCa5ZCR5p+Q5Liq6aKG5Z+f55qE5ZSv5LiA6YCU5b6E", "newM.sql");
System.out.println("success");
}
}
结果newM.sql文件内容竟是0字节,而控制台输出如下:
这种情况我以前也遇见过,今天就顺道讲讲,其实IO流关闭是有顺序讲究的,我让他把IOCloseUtil.close(fos, bos)改成IOCloseUtil.close(bos, fos)结果问题就顺利解决了,他问我是什么原因?因为未使用工具类以前,他的IO流关闭是这样的,测试也没问题,所以他还怀疑可能是IO流关闭工具类的问题:
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
我让他改一下顺序,先关闭fos,在关闭bos,结果执行就这样了:
所以,在关闭IO流时,一般讲究这样的顺序:后打开的先关闭,先打开的后关闭!
另外一种情况是跟依赖有关:依赖者先关闭,被依赖者后关闭!
比如如果流a依赖流b,应该先关闭流a,再关闭流b。例如字节流bos依赖字节流fos,应该先关闭bos,再关闭fos,不然会抛出IO异常。