第五小节之JAVA IO流
文件:文本文件是一种计算机文件,它是一种典型的顺序文件,其文件的逻辑结构又属于流式文件,特别的是指以ASCLL码方式(也称为文本方式)存储的文件,而更确切地说,英文、数字等字符存储的是ASCLL码,而汉字存储的是本机码。文本文件中除了存储文件有效字信息(包括能用ASALL码字符表示的回车、换行等信息)外,不能存储其它任何信息,
计算机的存储在物理上是二进制的所以文本文件与二进制文件的区别并不是物理上的,而是逻辑上。这两者只是在编码层次上有差异。
字节数组与字符串相互转换需要考虑编码
数据流:数据传输抽象表示为“流”,程序允许通过流的方式与输入输出设备进行数据传输。Java中的“流”都位于java.io包,称为IO(输入输出)流。
按照操作数据的不同,可以分为字节流和字符流,按照数据传输方向的不同又可分为输入流和输出流,程序从输入流中读取数据,向输出流中写入数据。在IO包中,字节流的输入输出流分别用java.io,InputStream和java.io.OutputStream表示,字符流的输入输出流分别用java.io.Reader和java.io.Writer表示
任何数据在底层保存为字节(不可再分)
ISO8859-1(ASCLL码)<=32属于不可见字符
GBK—国家标准
UTF-8 国际标准
1、字节流
在计算机中所有的文件都是以二进制字节形式存在,在JDk中,提供了两个抽象类InputStream和OutputStream,他们是字节流的顶级父类。
IO流中的输入输出都是相对程序而言的。
InputStream常用方法:
int read() 从输入流读取一个8位的字节,把它转换为0~255之间的整数,并返回这一整数
int read(byte[] b)从输入流读取若干字节,把它们保存到参数b指定的字节数组中,返回的整数表示读取字节数
int read(byte[] b,int off,int len)从输入流读取若干字节,把它们保存到参数b指定的字节数组中,off指定字节数组开始保存数据的起始下标,len表示读取的字节数目
void close() 关闭此输入流并释放与该流关联的所有系统资源
OutputStream常用方法:
void write(int b)向输出流写入一个字节
void write(byte[] b)把参数b指定的字节数组的所有字节写到输出流
void write(byte[] b,int off.int len)将指定byte数组中从偏移量off开始的len个字节写入输出流
void flush()刷新此输出流并强制写出所有缓冲的输出字节
void close()关闭此输出流并释放与此流相关的所有系统资源
注意:flush()方法用来将当前输出流缓冲区(通常是字节数组)中的数据强制写入目标设备,此过程称为刷新。
InputStream和OutputStream是抽象类,不能被实例化。
需要注意的是,在读取文件时,必须保证文件是存在并且可读的,否则会抛出文件找不到的异常FileNotFoundException。
在向一个已经存在的文件中写入数据,那么该文件中的数据首部首相会被清空,再写出新的数据。若希望在已存在的文件内容之后追加新内容,则可使用FileOutputStream的构造函数FileOutputStream(String fileName,boolean append)来创建文件输出流对象,并把append参数的值设置为true。
1 package stream; 2 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 import java.io.InputStream; 8 import java.io.OutputStream; 9 import java.util.Arrays; 10 /** 11 * 文件输入流 12 * @author Administrator 13 * 14 */ 15 public class CopyStreamDemo { 16 17 public static void main(String[] args) { 18 String srcFile = "F:\\MKing\\workspace\\IOPrj\\src\\stream\\FileInputStreamDemo.java";//目标文件,目录也可以用正斜线“/”表示两个左斜线“\\” 19 String destFile = "target.txt";//拷贝地址 20 try { 21 InputStream is = new FileInputStream(srcFile); 22 OutputStream os = new FileOutputStream(destFile); 23 byte[] buffer = new byte[100]; 24 int len = -1; 25 26 while ((len = is.read(buffer)) != -1) {//直到len的值为-1表示读取到了文件的末尾。结束循环 27 //System.out.println("Bytes: " + Arrays.toString(buffer)); 28 29 //String text = new String(buffer, 0, len, "ISO-8859-1"); 30 //System.out.print(text); 31 os.write(buffer, 0, len); 32 } 33 34 is.close(); 35 os.close(); 36 System.out.println("文件复制完成!"); 37 } catch (FileNotFoundException e) { 38 e.printStackTrace(); 39 } catch (IOException e) { 40 e.printStackTrace(); 41 } 42 43 } 44 45 }
1.1字节流的缓冲区:当通过流的方式拷贝文件时,为了提高效率也可以定义一个字节数组作为缓冲区
1 package stream; 2 3 import java.io.BufferedInputStream; 4 import java.io.BufferedOutputStream; 5 import java.io.FileInputStream; 6 import java.io.FileNotFoundException; 7 import java.io.FileOutputStream; 8 import java.io.IOException; 9 import java.io.InputStream; 10 import java.io.OutputStream; 11 import java.util.Arrays; 12 /** 13 * 文件输入流 14 * @author Administrator 15 * 16 */ 17 public class FileCopy { 18 19 public static void main(String[] args) { 20 String srcFile = "F:\\MKing\\eclipse-java-oxygen-3a-win32.zip"; 21 String destFile = "target.zip"; 22 try { 23 BufferedInputStream is = new BufferedInputStream(new FileInputStream(srcFile)); 24 BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(destFile)); 25 byte[] buffer = new byte[100]; 26 int len = -1; 27 System.out.println("正在复制文件,请稍候..."); 28 long begin = System.currentTimeMillis(); 29 while ((len = is.read(buffer)) != -1) {没循环一次,就从文件读取若干字节填充字节数组,并通过变量len记住读入数组的字节数,然后从数组的第一个字节开始,
将len个字节依次写入文件。循环往复,当len值为-1时,说明已经读到了文件的末尾,循环会结束,整个拷贝过程也就会结束。
30 //System.out.println("Bytes: " + Arrays.toString(buffer)); 31 32 //String text = new String(buffer, 0, len, "ISO-8859-1"); 33 //System.out.print(text); 34 os.write(buffer, 0, len); 35 } 36 37 long end = System.currentTimeMillis(); 38 is.close(); 39 os.close(); 40 System.out.println("文件复制完成!耗时:" + (end - begin) + " ms."); 41 } catch (FileNotFoundException e) { 42 e.printStackTrace(); 43 } catch (IOException e) { 44 e.printStackTrace(); 45 } 46 47 } 48 49 }
2字符流
字符流也有;两个抽象的顶级父类,分别是Reader和Writer
FileReader和FileWriter用于读写文件,BufferedReader和BufferedWriter是具有缓冲功能的流,它们可以提高读写xiaolv。
1 package chars; 2 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.FileOutputStream; 6 import java.io.FileReader; 7 import java.io.FileWriter; 8 import java.io.IOException; 9 import java.io.InputStream; 10 import java.io.OutputStream; 11 import java.io.Reader; 12 import java.io.Writer; 13 import java.util.Arrays; 14 /** 15 * 文件输入流 16 * @author Administrator 17 * 18 */ 19 public class CopyByCharsDemo { 20 21 public static void main(String[] args) { 22 String srcFile = "F:\\MKing\\实验报告.rar"; 23 String destFile = "target.rar"; 24 try { 25 Reader reader = new FileReader(srcFile); 26 Writer writer = new FileWriter(destFile); 27 char[] buffer = new char[100]; 28 int len = -1; 29 30 while ((len = reader.read(buffer)) != -1) { 31 writer.write(buffer, 0, len); 32 } 33 34 reader.close(); 35 writer.close(); 36 System.out.println("文件复制完成!"); 37 } catch (FileNotFoundException e) { 38 e.printStackTrace(); 39 } catch (IOException e) { 40 e.printStackTrace(); 41 } 42 43 } 44 45 }
1 package chars; 2 3 import java.io.BufferedReader; 4 import java.io.FileNotFoundException; 5 import java.io.FileReader; 6 import java.io.IOException; 7 import java.io.Reader; 8 /** 9 * 文件Reader 10 * @author Administrator 11 * 12 */ 13 public class BufferedReaderDemo { 14 15 public static void main(String[] args) { 16 String srcFile = "src\\chars\\FileReaderDemo.java"; 17 try { 18 BufferedReader br = new BufferedReader(new FileReader(srcFile)); 19 String line = null; 20 21 while ((line = br.readLine()) != null) {//该方法用于一次读取一行文本 22 System.out.println(line); 23 } 24 25 br.close(); 26 } catch (FileNotFoundException e) { 27 e.printStackTrace(); 28 } catch (IOException e) { 29 e.printStackTrace(); 30 } 31 32 } 33 34 }
转换流:InputStreamReader和OutputStreamWriter,字节和字符之间的转换
1 package chars; 2 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.FileReader; 6 import java.io.IOException; 7 import java.io.InputStreamReader; 8 import java.io.Reader; 9 /** 10 * 输入流Reader 11 * @author Administrator 12 * 13 */ 14 public class InputStreamReaderDemo { 15 16 public static void main(String[] args) { 17 String srcFile = "src\\chars\\FileReaderDemo.java"; 18 try { 19 Reader is = new InputStreamReader(new FileInputStream(srcFile), "GBK"); 20 char[] buffer = new char[100]; 21 int len = -1; 22 23 while ((len = is.read(buffer)) != -1) { 24 String text = new String(buffer, 0, len); 25 System.out.print(text); 26 } 27 28 is.close(); 29 } catch (FileNotFoundException e) { 30 e.printStackTrace(); 31 } catch (IOException e) { 32 e.printStackTrace(); 33 } 34 35 } 36 37 }
注意:在转换时,只能针对操作文本文件的字节流进行转换,如果字节流操作的是一张图片,此时转换为字符流就会造成数据丢失。
3ObjectInputStream和ObjectOutputStream
程序在运行时,会在内存中创建多个对象,然而程序结束后,这些对象便当做垃圾回收了。如果希望永久保存这些对象,则可以将对象转为字节数据写入到硬盘上,这个过程称为对象序列化。为此JDk提供了ObjectOutputStream(对象输出流)来实现对象的序列化。当对象进行序列化时,必须保证该对象实现Serializable接口,否则程序会出现NotSerializableException异常。Serializable接口没有抽象方法,只是一个标志
4DataInputStream和DataOutputStream:存储对象的成员数据,只有读取数据的顺序与写数据的顺序保持一致,才能保证最终数据的正确性
重定向:就是通过各种方法将各种网络请求重新定个方法转到其它位置。
5标准输入输出流
静态方法:
void setIn(InputStream in)对标准输入流重定向
void setOut(PrintStream out)对标准输出流重定向
void' setErr(PrintStream out)对标准错误流重定向
6FIle类:对文件本身进行一些常规的操作,JDK中提供了一个File类,该类封装了一个路径,并提供了一系列的方法用于操作该路径所指向的文件。
File内部封装的路径可以指向一个文件,也可以指向一个目录
构造方法:
File(String pathname)通过指定的一个字符串类型的文件路径来创建一个新的File对象
File(String parent, String child)根据指定的一个字符串类型的父路径和一个字符串类型的子路径(包括文件名称)创建一个File对象
File(File parent,String child)根据指定的File类的父路径和字符串类型的子路径(包括文件名称)创建一个File对象
常用方法:
7RandomAccessFile
前面介绍的IO流有一个共同的特点,就是只能按照数据的先后顺序读取源设备中数据,或者按照数据的先后顺序向目标设备写入数据。但如果希望从文件的任意位置开始执行读写操作,则字节流和字符流都无法实现。为此,在IO包中,提供了一个类RandomAccessFile,它不属于流类,但具有读写文件数据的功能,可以随机地从文件的任意位置开始执行读写数据的操作。
构造方法:
RandomAccessFile(File file,String mode)参数file指定被访问的文件
RandomAccessFile(String name,String mode)参数name指定被访问文件的路径
第一个参数指定关联的文件,第二个参数mode指定访问文件的模式。参数mode有四个值,最常用的有两个,分别是“r”和“rw”,其中“r”表示以只读的方式打开文件,如果视图对RandomAccessFile对象执行写入操作,会抛出IOException异常;“rw表示以只读”的方式打开文件,如果该文件不存在,则会自动创建该文件
常用方法:
long getFilePointer()返回当前读写指针所处的位置
void seek(long pos)设定读写指针的位置,与文件开头相隔pos个字节数
int skipBytes(int n)使读写指针从当前位置开始,跳过n个字节
void setLength(long newLength)设置此文件的长度
在RandomAccessFile对象中包含了一个记录指针,用于表示文件当前读写处的位置,当新创建一个RandomAccessFile对象时,该对象的文件记录指针位于文件头(也就是0处),当读写了n个字节后,文件的记录指针就会向后移n个字节。RandomAccessFile的seek(long pos)方法,可以使记录指针向前、向后自由移动,通过RandomAccessFIle的getFilePointer()方法,便可获得文件当前记录指针的位置。
8字符编码
在计算机之间,同样无法直接传输一个一个的字符,而只能传输二进制数据
在计算机程序中,如果要把字节数组转换为字符串,可以通过String类的构造方法String(byte[] bytes,Strinf charsetName)把字节数组按照指定的码表解码成字符串(如果没有指定字符码表,则用操作系统默认的字符码表,如中文的Windows系统默认使用的字符码表是GBK);反之,可以通过使用String类中的getBytes(String charsetName)方法把字符串按照指定的码表编码成字节数组。