I/O结构关系图
字节与字符的概念
字节 byte
计算机信息技术用于计量存储容量的一种计量单位,通常使用字节数组byte[]读取字节类型的文件。
FileInputStream:文件流的具体实现类,继承InputStream(流), 如下例子,将文件通过文件流实现类,转换为流。
FileOutputStream:文件流的具体实现类,继承OutputStream(流),例如 OutputStream os =
new FileOutputStream(file);
InputStream,OutputStream:输入/输出流。文件内容的写入通过其实现,读取通过BufferedInputStream.read()读取。
MultiPartFile: 一个接口,用于接收文件(前台传进来的文件),并通过transferTo(File)方法转换为文件,也可以MultiPartFile.getInputStream()获取文件流,路径,文件名等信息。
FileInputStream、FileOutputStream直接用于操作文件流的,进行文件与流的转换,是文件流的最直接操作类;
InputStream、OutputStream用于流内容的读取与写入,不能进行文件级别的信息操作。
字符 char
是指计算机中使用的文字和符号,通常使用字符数组char[]读取字符类型的文件。
InputStreamReader : 是字节流与字符流之间的桥梁,能将字节流输出为字符流,并且能为字节流指定字符集,可输出一个个的字符; 参数为InputStream类型,
BufferedReader : 提供通用的缓冲方式文本读取,readLine读取一个文本行, 从字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取。
BufferedWriter: 字符缓冲输出流,用于写文件,刷新,关闭流等操作。
FileWriter: 字符输出流,与bufferedWriter区别是,BufferedWriter有缓冲区8192个字符,缓冲8192个字符并查码表,FileWriter写一个查一次码表。
字符流 = 字节流 + 码表, 一字符 = 2字节
不管是字节流还是字符流,文件转换为流一定是通过fileInputStream转化并成为字节流,如果是字符流,则通过new inputStreamReader(InputStream in)转为字符流,框架里构造函数可录入多种形式的参数生成字符流,其实走的都是最底层的 public InputStreamReader(InputStream in)方法。
文件概念
-
文件名
文件在java中是一个实体,具有多种属性方法,常用包括获取文件路径(相对,绝对),获取文件名,获取父级路径。在文件实体中,文件名也作为文件路径的一部分。
例如
:
C:\\Users\\Administrator\D\esktop\\CNY15_20190925_001_022298.apk 这是一个完整的文件路径,也是完整的文件;
- 常用的文件操作方法
获取父级目录:使用getParent()方法可以获取父级路径,C:\Users\Administrator\Desktop,
创建目录:需要实例化一个File file = new File("filePath");file.mkdirs()方法,mkdirs可以创建父级目录,mkdir创建当前目录,例如C:\Users\Administrator\Desktop下创建 asdf 文件夹,使用mkdirs情况下,若无C:\\Users\\Administrator\\Desktop,则会创建;使用mkdir,若无C:\\Users\\Administrator\\Desktop,则目录不会创建。
检测目录:实例化file并使用exist()方法。
移动文件:files.move(源文件,目标文件),文件移走后源文件删除。
删除文件:files.delete()。
- 相对路径与绝对路径
相对路径: 两个文件处于同一目录下,则这两个文件成相对关系,如d:/a/abc.html与d:/a/b/bdeg.jpg,若该html需要引入此图片,路径直接填写b/bdeg.jpg即可。
绝对路径: 两个文件不处于同一目录下,则这两个文件成绝对关系,如需互相调用,则要填写完整路径。
-
注意事项
分隔符: windows与linux分隔符不同,windows为\\,linux为/,因为前后台路径的交互,可能会有分隔符转换的情况发生,需要注意;使用File.seperator代替分隔符,该方法会判定操作系统并进行适应。
I/O流: 对文件进行操作时,要注意是否有文件流存在,若该文件被解析成流,需要先关闭流。
-
文件下载
前台下载:页面使用a标签进行连接,后台使用输出流写文件。OutputStream out = response.getOutputStream(),注意如果使用http进行文件下载,则在该线程内就不能使用 http做页面响应了
后台下载:使用输出流OutputStream.write()继续下载,注意一定要使用write(byte b[], int off, int len),如果不录入写入长度length,很有可能写完的文件会多出一部分内容。
跨服务器下载: 可以使用sftp或ftp,可以参考sftp工具类或ftp工具类。
/**
* 使用http响应进行文件下载
* 例子
*
*/
@SuppressWarnings("unused")
public static String downloadFile(HttpServletRequest request, HttpServletResponse response,
String fileName, String path) {
if(fileName != null){
File file = new File(path);
if (file.exists()) {
try{
// 转码之后的文件名
String finalFileName = "";
// 获取客户端浏览器信息
String agent = request.getHeader("User-Agent");
// 是否为IE浏览器
boolean isMSIE = (agent != null && agent.indexOf("MSIE") != -1);
if (isMSIE) {
// IE浏览器下文件名
finalFileName = java.net.URLEncoder.encode(fileName, "UTF8");
} else {
// 其他浏览器下文件名
finalFileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
}
response.setHeader("Content-Disposition", "attachment; filename=\"" + finalFileName + "\"");
response.resetBuffer();
// 利用输出输入流导出文件
OutputStream sos = response.getOutputStream();
InputStream is = new FileInputStream(file);
byte[] b = new byte[1024];
int len;
while ((len = is.read(b)) > 0) {
sos.write(b,0,len);
}
// 关闭流
if (is != null) {
is.close();
}
sos.flush();
response.flushBuffer();
// 关闭流
sos.close();
return "success";
}catch(IllegalStateException | IOException e){
return "error";
}
}
}
return "field";
}
/*
* 例子
* 使用新文件内容重写旧文件(只针对字符流/文本文件)
* out = new BufferedWriter(new FileWriter(filePath, true))表示在原文件基础上继续编写
*/
BufferedWriter out = null;
String content = null;
out = new BufferedWriter(new FileWriter(filePath));
content = FileUtils.readFileToString(file, "GBK");
file.delete();
out.write(content);
out.flush();
out.close();
/*
* 例子
* 输入流转换为文件
*/
public static void inputStreamToFile(InputStream ins, File file) throws IOException {
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[128];
while ((bytesRead = ins.read(buffer)) != -1) {
os.write(buffer, 0 , bytesRead);
}
os.flush();
os.close();
ins.close();
}