IO流


1、IO流的类

2、流的分类

  • 按数据流的方向不同:输入流,输出流。
  • 按处理数据单位不同:字节流,字符流。
    (1) 字节流:数据流中最小的数据单元是字节。
    (2)字符流:数据流中最小的数据单元是字符, Java中的字符是Unicode编码,一个字符占用两个字节。
  • 按功能不同:节点流,处理流。
    (1)程序用于直接操作目标设备所对应的类叫节点流。
    (2)程序通过一个间接流类去调用节点流类,以达到更加灵活方便地读写各种类型的数据,这个间接流类就是处理流。

3、java流的类型及其区别

字符流和字节流。字节流继承inputStream和OutputStream,字符流继承自InputSteamReader和OutputStreamWriter。

输入流就是从外部文件输入到内存,输出流主要是从内存输出到文件。

区别:

实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作文件。

在字符流的操作中,所有的字符都是在内存中形成的,在输出前会将所有的内容暂时保存在内存之中,所以使用了缓冲区暂存数据。即当我们使用字符流时,没有调用flush()方法刷新或关闭流时自动刷新,无法输出内容。

  1. 大多数情况下使用字节流会更好,因为大多数时候 IO 操作都是直接操作磁盘文件,所以这些流在传输时都是以字节的方式进行的(图片等都是按字节存储的),使用字节流读取纯文本文件时,可能会出现乱码现象。
  2. 如果对于操作需要通过 IO 在内存中频繁处理字符串的情况使用字符流会好些,因为字符流具备缓冲区,提高了性能

4、什么是缓冲区?有什么作用?

  1. 缓冲区就是一段特殊的内存区域,很多情况下当程序需要频繁地操作一个资源(如文件或数据库)则性能会很低,所以为了提升性能就可以将一部分数据暂时读写到缓存区,以后直接从此区域中读写数据即可,这样就显著提升了性。
  2. 对于 Java 字符流的操作都是在缓冲区操作的,所以如果我们想在字符流操作中主动将缓冲区刷新到文件则可以使用 flush() 方法操作。

5、缓冲流(高效流)

(1)字符输入缓冲流

try {
    Reader reader = new FileReader("1.txt");
    //第一个参数是要增强的流,第二个参数是缓冲区(char[])大小,默认缺省8192
    BufferedReader br = new BufferedReader(reader,8192);

    //用于存储读取到的内容
    char[] c = new char[1024];
    //用于获取读取的长度,返回-1,即读取完毕
    int len = -1;
    //可拼接字符串
    StringBuilder sb=new StringBuilder();

    while((len = br.read(c)) != -1){
           //拼接字符串
        sb.append(new String(c,0,len));
    }
    System.out.println(sb);
    reader.close();
    br.close();
} catch (IOException e) {
    e.printStackTrace();
}

(2)字符输出缓冲流

StringBuilder sb = "hello world";

try {
    FileWriter writer = new FileWriter("2.txt");
    BufferedWriter bw = new BufferedWriter(writer);

    bw.write(sb.toString());

    //关闭顺序不可变
    bw.close();
    writer.close();


} catch (IOException e) {
    e.printStackTrace();
}

(3)字节输入/输出缓冲流

用法同上,size默认8192

//字节缓冲输入流
public BufferedInputStream(InputStream in, int size)

//字节缓冲输出流
public BufferedOutputStream(OutputStream out, int size)

文件下载

后端接口

@GetMapping("/download")
public void download(HttpServletRequest request, HttpServletResponse response) throws IOException {

    //1.获取要下载的文件的绝对路径
    String realPath = "H:\\图分类\\线稿\\3.jpg";
    //2.获取要下载的文件名
    String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);

    response.reset();// 必要地清除response中的缓存信息
    //表明响应数据为二进制流数据(如常见的文件下载)
    response.setContentType("application/octet-stream");
    //支持分段请求,断点续传
    response.setHeader("Accept-Ranges", "bytes");
    //3.设置content-disposition响应头控制浏览器以下载的形式打开文件
    response.setHeader("content-disposition", "attachment;filename="+ URLEncoder.encode(fileName, "UTF-8"));
    InputStream in = new FileInputStream(realPath);//获取文件输入流
    int len = 0;
    byte[] buffer = new byte[1024];
    OutputStream out = response.getOutputStream();
    while ((len = in.read(buffer)) > 0) {
        out.write(buffer,0,len);//将缓冲区的数据输出到客户端浏览器
    }
    in.close();
}

可将文件置于项目中,一起打包

// 动态获取当前类的绝对路径
// file:/G:/tc_work/tw-tms/trunk/teway-tms/target/classes/
URL url = this.getClass().getClassLoader().getResource("");

String fileName = "运输订单导入模板.xls";

// 拼接文件路径,文件存放在resource/templates/下
// G:\tc_work\tw-tms\trunk\teway-tms\target\classes\templates\运输订单导入模板.xls
String path = url.getPath() + "templates" + File.separator + fileName;

// 替换文件路径分隔符,win为\\ ,linux为/
// File.separator:系统默认的分隔符
path = path.replace("/", File.separator).replace("\\", File.separator);

前端

<a id="download3"  href="/download">下载</a>

<button onclick="download()">文件下载</button>

<script type="text/javascript">
    function download() {
        window.parent.open("/download");
        //window.parent.parent.open("/download"); //页面嵌套在其他页面的iframe里时
    }
</script>    

  目录