相对内存,分为两种
①输入流:输入到内存(目标)-------只关心源数据源
②输出流:从内存(源)输出 -------只关心目标数据源
按流传输基本单位,分为两种
①字节流:基本单位是字节(8位) 抽象类:InputStream OutputStream负责输入流及输出流
②字符流(Unicode):基本单位是16位Unicode字符 抽象类:Reader Writer负责输入流及输出流
使用时用子类实例化抽象类
这里需要注意一下:
1.BufferWriter是带有缓冲机制的,不会立即输出的,只有使用flush()或者close()函数时才会刷新缓冲区输出,换行需要调用newLine()。
2.BufferedReader是以行为单位读取的,调用readLine()函数,只有遇到换行符时才会读取。
案例一
案例二
serlvet项目
这里需要特别说明一下PrintWriter、BufferWriter的区别
BufferedWriter:将文本写入字符输出流,缓冲各个字符从而提供单个字符,数组和字符串的高效写入。通过write()方法可以将获取到的字符输出,然后通过newLine()进行换行操作。BufferedWriter中的字符流必须通过调用flush方法才能将其刷出去。并且BufferedWriter只能对字符流进行操作。如果要对字节流操作,则使用BufferedInputStream。
PrintWriter:向文本输出流打印对象的格式化表示形式(Prints formatted representations of objects to a text-output stream)。PrintWriter相对于BufferedWriter的好处在于,PrintWriter(out, autoFlush),autoFlush置为true时,当PrintWriter调用println,prinlf或format方法时,输出流中的数据就会自动刷新出去。PrintWriter不但能接收字符流,也能接收字节流。和PrintStream(OutputStream out,boolean autoFlush)不同的是,PrintStream每当输出遭到换行符,缓冲区的内容就全部输出,好像调用了多次flush(),而PrintWriter当且仅当调用了println,prinlf或format方法时,才会积极清缓冲区。
Socket编程中,尽量用PrintWriter取代BufferedWriter,下面是PrintWriter的优点:
1. PrintWriter的print、println方法可以接受任意类型的参数,而BufferedWriter的write方法只能接受字符、字符数组和字符串;
2. PrintWriter的println方法自动添加换行,BufferedWriter需要显示调用newLine方法;
3. PrintWriter的方法不会抛异常,若关心异常,需要调用checkError方法看是否有异常发生;
4. PrintWriter构造方法可指定参数,实现自动刷新缓存(autoflush);
5. PrintWriter的构造方法更广。
在使用BufferedReader中的readLine方法接收BufferedWriter中的字符流时,由于readLine是在读取到换行符的时候才将整行字符返回,所以BufferedWriter方法在录入一段字符后要使用newLine方法进行一次换行操作,然后再把字符流刷出去。而PrintWriter由于可以开启自动刷新,并且其中的println方法自带换行操作。所以代码实现起来要比BufferedWriter简单一些。PrintWriter和BufferedWriter都是继承java.io.Writer,所以很多功能都一样。不过PrintWriter提供println()方法可以写不同平台的换行符,而BufferedWriter可以任意设定缓冲大小。OutputStream可以直接传给PrintWriter(BufferedWriter不能接收)
这里需要说明一下:tomcat底层其实也是基于sokect编程的,就如我们的案例二,在一般情况下,没有调用flush()函数,服务端会等待整个业务逻辑处理完成后,再刷新缓冲区,前台才一下子显示出来整个html页面,也可以提前调用像案例二一样先显示页面一部分,当调用println()函数输出时,可以通过浏览器查看我们的页面源码,是有换行的,若调用的是print,则可以看到整个源码是无换行,挤在一行上的。
文件上传
以上情况特殊说明:以上是在单个文件未超过设置的最大内存的情况
文件上传:以php为例,可以通过修改apache的php.ini配置文件,设置最大内存,设置缓存目录,如果单个文件的大小超过最大内存,该文件将会临时缓存在指定的缓存目录下,该临时文件的保存期为脚本的周期,可以通过sleep(seconds)函数延迟PHP文件执行的时间,在目录中查看临时文件。如果文件小则会缓存在内存中。缓存成功后再使用io流复制转移到自己设定的位置,所以,当文件较小时,会看见系统内存升高。上传完成后界面会有停顿,停顿的这个过程就是在等待文件复制到指定目录这个过程,所以,要注意的是,服务端是无法将浏览器上传的文件,直接使用流的方式传到ftp的,因为servlet已经封装好了,上传的文件会直接先缓存到内存或临时目录中,服务端接着才能将文件写入到ftp中,所以如果要上传到ftp,浏览器停顿的时间会更久。
服务端生成文件后是可以直接输出到浏览器的,因为生成的文件其实也就是放在内存中,不需要本地保存后再使用流的方式输出到浏览器
考虑一下,嵌套IO流,是否应该从内到外依次关闭呢?
答案是不需要!这些IO类都是JDK自带的,调用了最外层的close方法,其实是一层一层向内调用了最内层的IO类的close方法,这也就是装饰者模式。
总结:c/s交互其实底层也是基于sokect网络编程,sokect基于tcp,交互的本身就是流的输入输出,并且使用的是printwriter输出流,带有缓冲机制,所谓的缓存机制,说通俗点,就比如先把一段字符串保存在一个数组中,数组的长度就是缓存区的大小,当调用flush函数清空缓存区时,其实就是清空数组,让字符串输出,就是这么简单。