一、IO流
流就是字节序列的抽象概念,能被连续读取数据的数据源和能被连续写入数据的接收端就是流,流机制是Java及
C++中的一个重要机制,通过流我们可以自由地控制文件、内存、IO设备等数据的流向。而IO流就是用于处理
设备上的数据,如:硬盘、内存、键盘录入等。
IO流根据处理类型的不同可分为字节流和字符流,根据流向的不同可分为输入流和输出流。
二、字节流和字符流
字符流,因为文件编码的不同,就有了对字符进行高效操作的字符流对象,它的原理就是基于字节流读取字节时
去查了指定的码表。它和字节流的区别有两点:1.在读取数据的时候,字节流读到一个字节就返回一个字节,
字符流使用了字节流读到一个或多个字节(一个中文对应的字节数是两个,在UTF-8码表中是3个字节)时,
先去查指定的编码表,再将查到的字符返回;2.字节流可以处理所有类型的数据,如jpg、avi、mp3、wav等等,
而字符流只能处理字符数据。所以可以根据处理的文件不同考虑使用字节流还是字符流,
如果是纯文本数据可以优先考虑字符流,否则使用字节流。
三、IO体系,整个java.io的核心都是采用了Decorator(装饰)模式。
1、字符流,Reader(读) Write(写),一个字符二个字节.
Reader中常见的方法:
int read();读取一个字符,并返回读到的这个字符,读到流的末尾则返回-1。
int read(char[]);将读到的字符存入指定的数组中,返回的是读到的字符个数,读到流的末尾则返回-1。
close();读取字符其实用的是window系统的功能,每次使用完毕后,需进行资源的释放。
Writer中常见的方法:
write();将一个字符写入到流中。
write(char[]);将一个字符数组写入到流中。
writer(String);将一个字符写入到流中。
flush();刷新流,将流中的数据刷新到目的地中,流还存在。
close();关闭资源,在关闭前会先调用flush(),刷新流中的数据到目的地。
2、字符流的缓冲区:
缓冲区的出现提高了对流的操作效率。原理:其实就是将数组进行封装。
对应的对象
(1)BufferedWriter
特有方法newLine(),跨平台的换行符。
(2)BufferedReader
特有方法readLine(),一次读一行,到行标记时,将行标记之前的字符数据作为字符串返回,读到末尾返回null。
说明:在使用缓冲区对象时,要明确,缓冲的存在是为了增强流的功能而存在,所以在建立缓冲区对象时,
要先有流对象存在。其实缓冲区内部就是在使用流对象的方法,只不过加入了数组对数据进行了临时存储,
为了提高操作数据的效率。
3、字节流(一个字节8个二进制位)
InputStream(读)
OutputStream(写)
由于字节是二进制数据,所以字节流可以操作任何类型的数据,值得注意的是字符流使用的是字符数组char[]
而字节流使用的是字节数组byte[]。
4、转换流
(1)特点:是字节流和字符流之间的桥梁,该流对象可以对读取到的字节数据进行指定编码表的编码转换。
(2)何时使用:当字节和字符之间有转换动作时或流操作的数据需要进行编码表的指定时。
(3)具体对象体现:
InputStreamReader: 字节到字符的桥梁
OutputStreamWriter:字符到字节的桥梁
说明:这两个流对象是字符流体系中的成员,它们有转换的作用,而本身又是字符流,所以在new的时候
需要传入字节流对象。
构造函数
InputStreamReader(InputStream),通过该构造函数初始化,使用的是系统默认的编码表GBK。
InputStreamReader(InputStream,String charset),通过该构造函数初始化,
可以通过charset参数指定编码。
OutputStreamWriter(OutputStream),使用的是系统默认的编码表GBK。
OutputStreamWriter(OutputSream,String charset),通过该构造函数初始化,
可以通过参数charset指定编码。
(4)操作文件的字符流对象是转换流的子类
|--Reader
|--InputStreamReader(转换流)
|--FileReader(文件字符流)
|--Writer
|--OutputStreamWriter(转换流)
|--FileWriter(文件字符流)
说明:转换流中的read方法,已经融入了编码表,在底层调用字节流的read方法时将获取的一个或者多个
字节数据进行临时存储,并去查指定的编码表,如果编码没有指定,则使用默认编码表。既然转换流已经完成了
编码转换的动作,对于直接操作的文本文件的FileReader而言,就不用再重新定义了,只要继承该转换流,
获取其方法,就可以直接操作文本文件中的字符数据了。
注意:在使用FileReader操作文本数据时,该对象使用的是默认的编码表,如果要使用指定的编码表,
必须使用转换流。
5、流操作的基本规律
(1)明确数据源和数据汇(数据目的),其实是为了明确是输入流还是输出流
(2)明确操作的数据是否是纯文本数据
说明:
数据源:键盘System.in、硬盘、File开头的流对象、内存(数组)。
数据汇:控制台System.out、硬盘、File开头的流对象、内存(数组)。
事例:将键盘录入的数据存储到一个文件中和打印到控制台
(1)数据源System.in
既然是源,使用的就是输入流,可用的体系有InputStream、Reader。
因为键盘录入进来的一定是纯文本数据,所以可以使用专门操作字符数据的Reader。
而System.in对应的流是字节读取流,所以要将其进行转换,将字节转换成字符即可,
所以要使用Reader体系中的InputStreamReader,如果要提高效率,就使用BufferedReader,代码如:
BufferedReader bur=new BufferedReader(newInputStreamReader(Sysem.in));
(2)数据汇:一个文件、硬盘
数据汇一定是输出流,可以用的体系有OutputStream、Writer。往文件中存储的都是文本数据,
那么可以使用字符流较为方便Writer。因为操作的是一个文件,所以使用Writer中的FileWriter,同理,
要提高效率就要使用BufferedWriter。代码如:
BufferedWriter bufr=new BufferedWriter(new FileWriter("test.txt"));
示例代码如下:将键盘录入的数据存储到一个文件中和打印到控制台代码
private static void test(){ BufferedReader bur=null; OutputStreamWriter osw=null; BufferedWriter bw=null; try{ //数据源 bur=new BufferedReader(new InputStreamReader(System.in)); //数据汇 osw=new OutputStreamWriter(System.out); //数据汇,因为数据源用的是系统默认编码,所以这里可以直接使用FileWriter //否则必须使用OutputStreamWriter转换流 bw=new BufferedWriter(new FileWriter("D:\\test_target.txt")); String line=null; while((line=bur.readLine())!=null){ osw.write(line); osw.flush();//刷新到控制台 bw.write(line); bw.flush();//刷新到文本文件 } }catch(IOException e){ e.toString(); }finally{ try{ if(osw!=null){ osw.close(); } if(bur!=null){ bur.close(); } if(bw!=null){ bw.close(); } }catch(IOException ex){ ex.toString(); } } }
四、IO流操作具体事例
/** * 字节流:FileInputStream,FileOutputStream * 字符流:FileReader,FileWriter * 缓冲流:BufferedInputStream,BufferedOutputStream(缓冲字节) * BufferedReader,BufferedWriter(缓冲字符) */ public class JavaIORead { /** * 以字节为单位读取文件,常用于读二进制文件,如图片、声音、影像等文件。 * (字节流:FileInputStream,FileOutputStream) */ public static void readFileByBytes(String fileName) { File file = new File(fileName); InputStream in = null; // 以字节为单位读取文件内容,一次读一个字节 try { System.out.println("以字节为单位读取文件内容,一次读一个字节:"); // 一次读一个字节 in = new FileInputStream(file); int tempbyte; // 读取到文件末尾则为-1 while ((tempbyte = in.read()) != -1) { // 直接写入到控制台 System.out.write(tempbyte); } in.close(); } catch (IOException e) { e.printStackTrace(); return; } // 以字节为单位读取文件内容,一次读多个字节,例如:一个汉字占二个字节,可一次读取二个字节 // 才能正常显示。 try { System.out.println("以字节为单位读取文件内容,一次读多个字节:"); // 一次读多个字节 byte[] tempbytes = new byte[100]; int byteread = 0; in = new FileInputStream(fileName); JavaIORead.showAvailableBytes(in); // 读入多个字节到字节数组tempbytes中,byteread为一次读入的字节数(实际读取的) StringBuffer strb = new StringBuffer(); while ((byteread = in.read(tempbytes)) != -1) { // 必须写入0到byteread,否则读取的内容则为整个tempbytes,或包含空串。 System.out.write(tempbytes, 0, byteread); // 转化为字符形式输出(需进行编码转换,编码与文件本身的编码一致) String str = new String(tempbytes, "utf-8"); strb.append(str); } System.out.println(strb.toString()); } catch (Exception e1) { e1.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException e1) { } } } } /* * 以字符为单位读取文件,常用于读文本,数字等类型的文件 * (字符流:FileReader,FileWriter) * */ public static void readFileByChars(String fileName) { File file = new File(fileName); Reader reader = null; try { System.out.println("以字符为单位读取文件内容,一次读一个字符:"); // 一次读一个字符,可用FileReader再进行外包装 reader = new InputStreamReader(new FileInputStream(file), "GBK"); int tempchar; while ((tempchar = reader.read()) != -1) { // 对于windows下,这两个字符在一起时,表示一个换行。 // 但如果这两个字符分开显示时,会换两次行。 // 因此,屏蔽掉,或者屏蔽。否则,将会多出很多空行。 // if (((char) tempchar) != ' ') { System.out.print((char) tempchar); // } } reader.close(); } catch (Exception e) { e.printStackTrace(); } try { System.out.println("以字符为单位读取文件内容,一次读多个字符:"); // 一次读多个字符 char[] tempchars = new char[30]; int charread = 0; // 在inputStreamReader上构造inputStream,并进行编码转换 reader = new InputStreamReader(new FileInputStream(fileName), "GBK"); // 读入多个字符到字符数组中,charread为一次读取字符数 while ((charread = reader.read(tempchars)) != -1) { // 同样屏蔽掉不显示 if ((charread == tempchars.length) && (tempchars[tempchars.length - 1] != ' ')) { System.out.print(tempchars); } else { for (int i = 0; i < charread; i++) { if (tempchars[i] == ' ') { continue; } else { System.out.print(tempchars[i]); } } } } } catch (Exception e1) { e1.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e1) { } } } } /** * 以行为单位读取文件,常用于读面向行的格式化文件 */ public static void readFileByLines(String fileName) { File file = new File(fileName); BufferedReader reader = null; try { System.out.println("以行为单位读取文件内容,一次读一整行:"); // 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取, // 用来包装reader. reader = new BufferedReader(new FileReader(file)); String tempString = null; int line = 1; // 一次读入一行,直到读入null为文件结束 while ((tempString = reader.readLine()) != null) { // 显示行号 System.out.println("line " + line + ": " + tempString); line++; } reader.close(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e1) { } } } } /** * 随机读取文件内容 */ public static void readFileByRandomAccess(String fileName) { RandomAccessFile randomFile = null; try { System.out.println("随机读取一段文件内容:"); // 打开一个随机访问文件流,按只读方式 randomFile = new RandomAccessFile(fileName, "r"); // 文件长度,字节数 long fileLength = randomFile.length(); // 读文件的起始位置 int beginIndex = (fileLength > 100) ? 100 : 0; // 将读文件的开始位置移到beginIndex位置。 randomFile.seek(beginIndex); byte[] bytes = new byte[10]; int byteread = 0; // 一次读10个字节,如果文件内容不足10个字节,则读剩下的字节。 // 将一次读取的字节数赋给byteread while ((byteread = randomFile.read(bytes)) != -1) { System.out.write(bytes, 0, byteread); } } catch (IOException e) { e.printStackTrace(); } finally { if (randomFile != null) { try { randomFile.close(); } catch (IOException e1) { } } } } /** * 缓冲读取文件内容,提升读取效率 * */ public static void readFileByBuffer(String fileName) throws Exception { File file = new File(fileName); InputStream is = new BufferedInputStream(new FileInputStream(file)); long length = file.length(); if (length > Integer.MAX_VALUE) { System.out.println("source file is too large"); return; } byte[] bytes = new byte[(int) length]; int offset = 0, numRead = 0; StringBuffer strBuff = new StringBuffer(); while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset))>= 0){ offset += numRead; String str = new String(bytes, "utf-8"); strBuff.append(str); } System.out.println(strBuff.toString()); if (offset < bytes.length) throw new IOException("Could not completely read file" + file.getName()); is.close(); } /** * 重定向标准的按制台输入输出 * */ public static void setSystemStream() throws FileNotFoundException { PrintStream output = new PrintStream(new FileOutputStream("c:/out.log")); System.setOut(output); PrintStream errOutput = new PrintStream(new FileOutputStream( "c:/err.log")); System.setErr(errOutput); System.out.println("Output redirect test"); System.err.println("Error redirect test"); // 原来在控制台输出的文字都将被写入out.log或err.log文件中 } /** * 读取对象,对角的可串行化 * * @throws Exception */ public static void readFileByObject() throws Exception { // User对象需序列化(implements Serializable) User user1 = new User("1001", "张三", 25); User user2 = new User("1002", "李四", 30); FileOutputStream fos = new FileOutputStream("c:/user.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(user1); oos.writeObject(user2); oos.close(); FileInputStream fis = new FileInputStream("c:/user.txt"); ObjectInputStream ois = new ObjectInputStream(fis); for (int i = 0; i < 2; i++) { User user = (User) ois.readObject(); System.out.println("userName:" + user.getName() + " age:" + user.getAge()); } ois.close(); } /** * 复制文件 */ public static void copyFile() { BufferedReader bur = null; BufferedWriter buw = null; try { bur = new BufferedReader(new InputStreamReader(new FileInputStream( "D:\\test_source.txt"), "UTF-8")); buw = new BufferedWriter(new OutputStreamWriter( new FileOutputStream("D:\\test_target.txt"), "UTF-8")); String line = null; while ((line = bur.readLine()) != null) { buw.write(line); buw.flush();// 刷新到文本文件 } } catch (IOException e) { e.printStackTrace(); } finally { try { if (buw != null) { buw.close(); } if (bur != null) { bur.close(); } } catch (IOException ex) { ex.toString(); } } } /** * 显示输入流中还剩的字节数 * */ private static void showAvailableBytes(InputStream in) { try { // available()方法为返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取 // (或跳过)的估计剩余字节数 System.out.println("当前字节输入流中的字节数为:" + in.available()); } catch (IOException e) { e.printStackTrace(); } } }
相关推荐
Java中的IO流是Java语言处理输入输出操作的重要组成部分,它为数据传输提供了强大的支持。本文将深入探讨Java的IO流实例应用,旨在帮助开发者更好地理解和掌握这一关键概念。 IO流在Java中分为两大类:字符流...
在这份《Java之IO流学习总结》文档中,我们可以了解到IO流的不同使用场景和基本的编程操作。 首先,我们来认识IO流中的基本类。在Java中,所有与IO相关的类都位于java.io包中。主要的抽象基类有InputStream、...
总之,Java的IO流是其强大的功能之一,提供了丰富的类和接口来满足各种输入输出需求。理解并熟练掌握IO流,对于Java开发人员来说至关重要,无论是在处理文件操作、网络通信还是数据存储方面,都能发挥出巨大的作用。
Java的IO流是Java编程语言中的重要组成部分,它主要用于数据的输入和输出操作。在Java中,IO流被设计为处理任何类型的数据,包括字符、字节甚至对象。本练习旨在帮助初学者理解和掌握Java IO流的基础知识。 一、IO...
### Java IO流详解 #### 一、流的概述与分类 在Java中,流是一种抽象概念,用于描述数据从一个地方传输到另一个地方的过程。它主要用于处理数据输入和输出,例如从磁盘读取文件、向网络发送数据或从键盘接收用户...
Java中的IO流是Java核心库的重要组成部分,它用于在不同数据源之间传输数据。Java IO流分为两大类:字符流(Character Stream)和字节流(Byte Stream)。字符流处理单个字符,而字节流处理8位的字节序列。它们又...
Java的IO流是程序与外部交互数据的重要工具,它允许开发者实现数据的读取、写入、复制和转换。在Java中,流被分为两类:字节流(Byte Stream)和字符流(Character Stream),它们都是Java IO体系的一部分。 字节流...
### Java IO流基础知识点 #### 一、IO流概述 - **定义**:在Java中,IO流(Input/Output Streams)是用来处理输入输出的基本工具。流是一种有序的数据集合,通常涉及从源到目的地的数据传输过程。源可以是文件、...
JAVA_IO流学习总结
Java_IO流详解 Java 的核心库 java.io 提供了全面的 IO 接口,包括文件读写、标准设备输出等。Java 中 IO 是以流为基础进行输入输出的,所有数据被串行化写入输出流,或者从输入流读入。在项目开发中,IO 是非常...
Java 中文件 IO 流 Java 中文件 IO 流是指 Java 语言中对文件的输入输出操作,通过定义文件流来实现文件的读写操作。文件流是指在程序中用于文件输入输出的对象, Java 中提供了多种文件流类型,包括 InputStream ...
理解并熟练运用Java的IO流体系,不仅可以提高代码的可读性和效率,也是成为一名专业Java开发者必备的技能之一。在实际项目中,我们经常会遇到需要对文件进行读写、在网络间传输数据或处理用户输入的情况,这时候,...
java基础中的IO流是Java提供的一套用于文件读写操作的流式API,它包括字节流和字符流两种基本类型。字节流主要用在处理二进制数据,而字符流则是处理文本数据。 首先,文档中提到了`File`类,它是IO流操作中用于...