【Java基础知识】IO流--字节流读写数据以及复制文件的几种方式
2017-01-18 15:55
821 查看
1、IO的分类
A、按照流向【参照物JVM】输入流 : 读取数据
输出流 : 写出数据
B、按照数据类型
(1)字节流
a、字节输入流 读取数据 InputStream
b、字节输出流 写出数据 OutputStream
(2)字符流
a、字符输入流 读取数据 Reader
b、字符输出流 写出数据 Writer
注意:一般我们在探讨IO流的时候,如果没有明确说明按哪种分类来说,默认情况下是按照数据类型来分的。
注意:每种基类的子类都是以父类名作为后缀名。
XxxOutputStream
XxxInputStream
XxxReader
XxxWriter
2、字节流的抽象父类 及基本方法
InputStream【抽象类】输入流:JVM从中连续读取字节的对象。int read():从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值,如果返回-1表示遇到流的末尾,结束。 int read(byte[] b):读入b.length个字节放到b中,并返回实际读入的字节。 int read(byte[] b,int off,int len):这个方法表示把流中的数据读到,数组b中,第off个开始的len个数组元素中。 void close():在操作完一个流后要使用此方法将其关闭, 系统就会释放与这个流相关的资源。
OutputStream【抽象类】输出流:JVM向其中连续写入的对象。
void write(int b):将指定的字节写入此输出流。 void write(byte[] b):将 b.length 个字节从指定的 byte 数组写入此输出流。 void write(byte[] b,int off, int len):将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。 void flush():刷新此输出流,并强制写出所有缓冲的输出字节。【彻底完成输出并清空缓冲区】。
3、为何需要调用close()方法?为什么需要缓冲?使用缓冲区技术的优缺点?
3.1为什么需要调用close()方法?
尽管在调用流对象的,在没有引用变量指向它时会变成垃圾,最终垃圾回收器会自动回收。在程序创建一个IO流对象,除了Java程序中我们可见的实例对象外,还有系统本身的资源,Java垃圾回收器只能管理程序中的类的实例对象,没法去管理系统产生的资源,所以程序需要调用close方法,去通知系统释放其自身产生的资源。3.2 为何血需要缓冲区?缓冲技术的优缺点?
计算机访问外部设备,要比直接访问内存慢得多,如果我们每一次write方法的调用都直接写到外部设备(如直接写入硬盘文件),CPU就要花费更多的时间等待外部设备;如果我们开辟一个内存缓冲区,程序的每一次write方法都是写到这个内存缓冲区中,只有这个缓冲区被装满后,系统才将这个缓冲区的内容一次集中写到外部设备。优点:有效的提高了CPU效率。
缺点:由于缓冲区,数据并没有立即写入到目标中去,就会造成一定的滞后。
缓冲区技术的实现是由编程语言本身决定的:
C语言:默认情况下就会使用缓冲区。
Java:有的类使用了缓冲区,有的类没有使用缓冲区。
flush()方法在缓冲区没有满的情况下,也将缓冲区的内容强制写入外设【刷新】。在调用close()方法,系统在关闭这个流之前也会将缓冲区的内容刷新到硬盘文件。
4、OutputStream输出流的write()方法使用
如何向文本中写入字节?如何实现数据追加?如何实现数据换行?4.1 直接写入字节
public class FileOutputStreamDemo { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("IO.txt"); fos.write("hello,IO".getBytes());//获取本地编码的字节数组,并写入文本文件中。 fos.write("java".getBytes()); fos.close(); } } /* IO.txt的内容: hello,IOjava */
4.2 写入字节的3种方式
public class FileOutputStreamDemo2 { public static void main(String[] args) throws IOException { //如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。 FileOutputStream fos = new FileOutputStream("IO.txt", true); fos.write(65); //65 -- 底层二进制数据 -- 通过记事本打开 -- 找65对应的字符值 -- a byte[] bys={97,98,99,100,101}; fos.write(bys); fos.write(bys,1,3); fos.close(); } } /* IO.txt文本的内容: Aabcdebcd */
4.3关于数据换行
不同的系统针对不同的换行符号识别是不一样的。1、windows:\r\n
2、linux:\n
3、Mac:\r
public class FileOutputStreamDemo3 { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("IO.txt", true); // 写数据 for (int x = 0; x < 3; x++) { fos.write(("Hello Java" + x).getBytes()); fos.write("\r\n".getBytes()); } fos.close(); } } /* IO.txt文本的内容: Hello Java0 Hello Java1 Hello Java2 */
4.4 IO流异常处理的代码
开发中还必须考虑异常处理情况下的输入流的操作public class FileOutputStreamDemo4 { public static void main(String[] args) { //为了在finally里面能够看到该对象就必须定义到外面,为了访问不出问题,还必须给初始化值 FileOutputStream fos = null; try { fos = new FileOutputStream("IO.txt"); fos.write("Java,Hello".getBytes()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { //如果fos不是null,才需要close() if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
5、InputStream输入流的read()方法使用
输入流操作public class FileInputStreamDemo { public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("IO.txt"); int by = 0; //读取,赋值,判断 while ((by = fis.read()) != -1) { System.out.print((char)by); } fis.close(); } }
6、通过IO流进行文件复制
6.1 基本的文件复制
public class CopyFileDemo { public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("a.txt"); FileOutputStream fos = new FileOutputStream("b.txt"); int by = 0; while ((by = fis.read()) != -1) { fos.write(by); } fos.close(); fis.close(); } }
6.2 计算机是如何识别应该把2个字节转换为一个汉字?
在GBK字符编码集中,汉字是由2个字节组成,因为GBK兼容ISO-8859-1,正数的单字节已被占用所以汉字的第一个字节必须为负数第二个字节大多也为负数。如:
public class StringDemo { public static void main(String[] args) throws UnsupportedEncodingException { String s1 = "Xyz123"; String s2 = "手可摘星辰"; byte[] bys1 = s1.getBytes(); byte[] bys2 = s2.getBytes(); System.out.println(Arrays.toString(bys1)); System.out.println(Arrays.toString(bys2)); } } /* GBK编码字符集下: [88, 121, 122, 49, 50, 51] [-54, -42, -65, -55, -43, -86, -48, -57, -77, -67] * */
6.3 IO操作时定义一个字节数组作为缓存
public class CopyFileDemo { public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("c:\\a.txt"); FileOutputStream fos = new FileOutputStream("d:\\b.txt"); byte[] bys = new byte[1024]; int len = 0; while ((len = fis.read(bys)) != -1) { fos.write(bys, 0, len); } fos.close(); fis.close(); } }
6.5 通过带有缓冲区的字节类【高效类】
写数据:BufferedOutputStream读数据:BufferedInputStream
看源码:
BufferedOutputStream 继承【过滤流】 FilterOutputStream。进一步地重写过滤流方法中的一些方法,并且还可以提供一些额外的方法和字段。
FilterOutputStream继承自抽象类OutputStream,过滤类本身只是简单地重写那些将所有请求传递给所包含输出流的 OutputStream 的所有方法。
实际上把缓冲写在包装在类中,BufferedInputStream原理类似。
通过定义数组的方式比一次读取一个字节的方式快很多,拥有缓冲区效率提升很多。
Java在设计时提供缓冲区的字节类BufferedOutputStream和BufferedInputStream。
真正的底层读写数据还是依靠基本流对象来实现,见源码解析。
【BufferedOutputStream】源代码解析
public class BufferedOutputStream extends FilterOutputStream { protected byte buf[]; //内部缓冲区 protected int count; //缓冲区存储的字节个数 public BufferedOutputStream(OutputStream out) { this(out, 8192); } public BufferedOutputStream(OutputStream out, int size) { super(out); if (size <= 0) { throw new IllegalArgumentException("Buffer size <= 0"); } buf = new byte[size];//开辟一个缓冲区 } //刷新内部缓冲区 private void flushBuffer() throws IOException { if (count > 0) { out.write(buf, 0, count); count = 0; } } //将指定的字节写入此缓冲的输出流 public synchronized void write(int b) throws IOException { if (count >= buf.length) { flushBuffer(); } buf[count++] = (byte)b; } //将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流 public synchronized void write(byte b[], int off, int len) throws IOException { if (len >= buf.length) { flushBuffer(); out.write(b, off, len); return; } if (len > buf.length - count) { flushBuffer(); } System.arraycopy(b, off, buf, count, len); count += len; } public synchronized void flush() throws IOException { flushBuffer(); out.flush(); } }
6.7 比较4中IO复制操作的效率
/* * 需求:把F:\\红玫瑰.mp3【9.25M】复制到当前项目目录下的copy.mp4中 */ public class CopyMp4Demo { public static void main(String[] args) throws IOException { long start = System.currentTimeMillis(); method4("F:\\红玫瑰.mp3", "copy.mp3"); long end = System.currentTimeMillis(); System.out.println("共耗时:" + (end - start) + "毫秒"); } //1、基本字节流一次读写一个字节 public static void method1(String srcString, String destString)throws IOException { FileInputStream fis = new FileInputStream(srcString); FileOutputStream fos = new FileOutputStream(destString); int by = 0; while ((by = fis.read()) != -1) { fos.write(by); } fos.close(); fis.close(); } //2、基本字节流一次读写一个字节数组 public static void method2(String srcString, String destString)throws IOException { FileInputStream fis = new FileInputStream(srcString); FileOutputStream fos = new FileOutputStream(destString); byte[] bys = new byte[1024]; int len = 0; while ((len = fis.read(bys)) != -1) { fos.write(bys, 0, len); } fos.close(); fis.close(); } //3、高效字节流一次读写一个字节: public static void method3(String srcString, String destString)throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcString)); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destString)); int by = 0; while ((by = bis.read()) != -1) { bos.write(by); } bos.close(); bis.close(); } //4、高效字节流一次读写一个字节数组: public static void method4(String srcString, String destString)throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcString)); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destString)); byte[] bys = new byte[1024]; int len = 0; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } bos.close(); bis.close(); } } /* * 字节流4种方式复制文件所耗费的时间: * method1基本字节流一次读写一个字节: 共耗时:115906毫秒 * method2基本字节流一次读写一个字节数组:共耗时:342毫秒 * method3高效字节流一次读写一个字节: 共耗时:550毫秒 * method4高效字节流一次读写一个字节数组:共耗时:61毫秒 **/
7、IO流字符集可能出现的乱码
/* * 字节流读取中文可能出现的乱码问题: * a.txt文件的具体内容 * 手可摘星辰 * 2017.01.18.Java */ public class FileInputStreamDemo { public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("a.txt"); /*//读取数据,英文正常,中文乱码异常。【此方案仅对单字节字符有效】 int by = 0; while ((by = fis.read()) != -1) { System.out.print((char) by); } */ /*运行结果:?????????? 2017.01.18.Java */ //解决:采用系统默认的编码字符集 byte[] bys = new byte[1024]; int len = 0; while ((len = fis.read(bys)) != -1) { System.out.print(new String(bys, 0, len)); } fis.close(); /* 手可摘星辰 * 2017.01.18.Java*/ } }
关于字符串的编解码说明
/* * 乱码产生原因:编解码采用不同方案所致。 * 解决方案:编解码采用同一套字符集。 * 编码:byte[] -- String : new String(byte[] bytes, String CharsetName ) * 解码:String -- byte[] : getBytes(String CharsetName); * */ public class StringDemo { public static void main(String[] args) throws UnsupportedEncodingException { String s = "中国"; byte[] bys1 = s.getBytes(); byte[] bys2 = s.getBytes("GBK"); byte[] bys3 = s.getBytes("UTF-8"); System.out.println(Arrays.toString(bys1)); System.out.println(Arrays.toString(bys2)); System.out.println(Arrays.toString(bys3)); String s1 = new String(bys1); String s2 = new String(bys2, "GBK"); String s3 = new String(bys3, "UTF-8"); System.out.println(s1); System.out.println(s2); System.out.println(s3); } } /* 运行结果: [-42, -48, -71, -6] [-42, -48, -71, -6] [-28, -72, -83, -27, -101, -67] 中国 中国 中国 * *
相关文章推荐
- 【Java基础知识】IO类--字符流读写数据以及复制文件的几种方式
- Java基础之IO流,以字节流的方式操作读写文件FileOutputStream和FileInputStream的使用
- Java基础知识强化之IO流笔记49:IO流练习之 复制指定目录下指定后缀名的文件并修改名称的案例
- Java基础知识强化之IO流笔记34:OutputStreamWriter(Writer字符流的子类)5种write数据方式
- JAVA基础再回首(二十一)——递归、IO流概述、字节流写数据、读取数据、复制数据、字节缓冲流
- Java基础---Java---网络编程---TCP、UDP、UDP-键盘录入方式数据、Socket、TCP复制文件、UDP-聊天
- Java基础知识强化之IO流笔记43:IO流练习之 复制文本文件的 5 种方式案例
- Java基础---Java---网络编程---TCP、UDP、UDP-键盘录入方式数据、Socket、TCP复制文件、UDP-聊天
- Java基础知识强化之IO流笔记30:字节流4种方式复制mp4并测试效率
- Java基础之IO流,通过字节流缓冲区进行媒体文件的复制操作
- Java基础知识强化之IO流笔记35:InputStreamReader(Reader字符流的子类)2种read数据方式
- Java基础小知识1——分别使用字节流和字符流复制文件
- Java基础之IO流,通过字节流对媒体文件进行复制操作
- Java基础知识之文件操作(二)——IO流复制文件
- Java基础知识强化之IO流笔记44:IO流练习之 复制图片的 4 种方式案例
- java字节流的方式复制一个文件,按数组读取和写入
- Java IO读写大文件的几种方式及测试
- 黑马程序员_Java基础_IO流_字节流,字节流操作文件,缓冲区字节流,流的使用规律,异常记录原理
- JAVA基础,IO流。(文件复制的实现)
- Java基础---Java---IO流-----LineNumberReader方法及原理、自定义一个LineNumberReader、字节流、图片复制、mp3复制、