18天-06-IO流
字节流和字符流
字节流两个基类:
InputStream,FileInputStream,BufferedInputStream
OutputStream,FileOutputStream,BufferedOutputStream
PrintStream (打印字节流,带编码格式)
字符流两个基类:
Reader,FileReader,BufferedReader,InputStreamReader(字节流转换为字符流读取,带编码格式)
Writer,FileWriter,BufferedWriter,OutputStreamWriter(字节流转换为字符流写入,带编码格式)
PrintWriter (打印字符流,带编码格式)
流操作规律讲解:
源设备: 键盘 System.in; 硬盘 FileStream; 内存 ArrayStream;
目的设备: 控制台 System.out; 硬盘 FileStream; 内存 ArrayStream;
字符流:(只能用于文本文件)
操作FileWriter写入文件:
1.创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。而且该文件会被创建到指定目录下。如果该目录下已经有同名文件,将被覆盖。其实该步骤就是在明确数据要存放的目的地。
FileWriter fw=new FileWriter("filePath",true); //ture代表不覆盖已有文件,并在已有文件末尾添加数据
2.调用write()方法,将字符串写入到流中。
3.刷新流对象中缓冲的数据到文件里。
4.关闭流资源。在关闭流前,会刷新一次内部缓冲区的数据。
操作FileReader读取文件:
1.创建一个文件读取流对象,和指定名称的文件。要保证该文件是已经存在,如果不存在,会发生FileNotFoundException异常。 FileReader fr=new FileReader(FilePath);
2.调用读取流对象的read方法。read();一次读取一个字符,而且会自动往下读取。
第二种通过字符数组进行读取。
定义一个数组,用于存储读取到的字符,读取read(char[])返回的是读取到的字符个数。
复制的原理:其实就是将一个地方的文件数据存储到另外一个指定的地方。
字符流拷贝文件示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * 拷贝文件 3 * 4 * @param sourceFile 源文件路径 5 * @param targetFile 目标文件路径 6 */ 7 public static void copyFile(String sourceFile, String targetFile) 8 { 9 FileReader fr = null; //读文件 10 FileWriter fw = null; //写文件 11 try 12 { 13 fr = new FileReader(sourceFile); 14 fw = new FileWriter(targetFile); 15 16 char[] temp = new char[1024]; 17 int length = 0; 18 while ((length = fr.read(temp)) != -1) 19 { 20 //length是每次读取文件时返回已读取的字符数量,-1为文件读取完毕 21 fw.write(temp, 0, length); 22 } 23 } 24 catch (IOException e) 25 { 26 e.printStackTrace(); 27 } 28 finally 29 { 30 try 31 { 32 if (fr != null) 33 { 34 fr.close(); 35 } 36 } 37 catch (IOException e) 38 { 39 e.printStackTrace(); 40 } 41 try 42 { 43 if (fw != null) 44 { 45 fw.close(); 46 } 47 } 48 catch (IOException e) 49 { 50 e.printStackTrace(); 51 } 52 } 53 }
缓冲区: BufferedWriter,BufferedReader
缓冲区的出现是为了提高流的操作效率。所以在创建缓冲区之前,必须要先有流对象。
1.创建流对象(FileReader,FileWriter);
2.将需要提高效率的流对象作为参数传递给缓冲区的构造函数即可;
3.读写数据,并即时刷新缓冲区数据;
4.关闭缓冲区,流对象,缓冲区关闭时会检测一下数据是否写完,所以要后关闭流对象。
字符读取流缓冲区:该缓冲区提供了一个一次读一行的方法readLine(),当返回null时,表示读取到文件末尾。
readLine方法返回的时候只返回回车符之前的数据内容,并不返回包含回车符。
readLine原理:无论是读一行还是读取多个字符,其实最终都是在硬盘上一个一个读取,所以最终使用的还是read()方法一次读一个。
缓冲区提供了一个跨平台的换行符:newLine();
缓冲区拷贝文件示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * 缓冲区拷贝文件 3 * 4 * @param sourceFile 源文件路径 5 * @param targetFile 目标文件路径 6 */ 7 public static void copeFileByBuffer(String sourceFile, String targetFile) 8 { 9 BufferedReader bufr = null; 10 BufferedWriter bufw = null; 11 try 12 { 13 bufr = new BufferedReader(new FileReader(sourceFile)); 14 bufw = new BufferedWriter(new FileWriter(targetFile)); 15 String temp = null; 16 while ((temp = bufr.readLine()) != null) 17 { 18 bufw.write(temp); 19 bufw.newLine(); 20 bufw.flush(); 21 } 22 } 23 catch (FileNotFoundException e) 24 { 25 e.printStackTrace(); 26 } 27 catch (IOException e) 28 { 29 e.printStackTrace(); 30 } 31 finally 32 { 33 try 34 { 35 if (bufr != null) 36 { 37 bufr.close(); 38 } 39 } 40 catch (IOException e) 41 { 42 e.printStackTrace(); 43 } 44 try 45 { 46 if (bufw != null) 47 { 48 bufw.close(); 49 } 50 } 51 catch (IOException e) 52 { 53 e.printStackTrace(); 54 } 55 } 56 }
装饰设计模式:当想要对已有的对象进行功能增强时,可以定义类将已有对象传入,基于已有的功能,并提供增强功能。那么自定义的该类称为装饰类。
装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
装饰类因为增强了已有的对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰类通常是都属于一个体系中的。
装饰模式比继承要灵活,避免了继承体系臃肿,而且降低了类与类之间的关系。
字节流:
int read():读取时返回int类型,会把byte字节提升为int类型,提升方式是byte&0xff,在写入时也做了反向操作强转为byte类型。防止类型提升导致原本不是 -1 的数据在类型提升后变成 -1。
字节流复制文件示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * 字节流方式拷贝文件 3 * 4 * @param sourceFile 源文件路径 5 * @param targetFile 目标文件路径 6 */ 7 public static void copyFileByByte(String sourceFile, String targetFile) 8 { 9 BufferedInputStream bfis = null; 10 BufferedOutputStream bfos = null; 11 try 12 { 13 bfis = new BufferedInputStream(new FileInputStream(sourceFile)); 14 bfos = new BufferedOutputStream(new FileOutputStream(targetFile)); 15 byte[] temp = new byte[1024*1024]; 16 int length; 17 while ((length = bfis.read(temp)) != -1) 18 { 19 bfos.write(temp, 0, length); 20 } 21 } 22 catch (FileNotFoundException e) 23 { 24 e.printStackTrace(); 25 } 26 catch (IOException e) 27 { 28 e.printStackTrace(); 29 } 30 finally 31 { 32 try 33 { 34 if (bfis != null) 35 { 36 bfis.close(); 37 } 38 } 39 catch (IOException e) 40 { 41 e.printStackTrace(); 42 } 43 try 44 { 45 if (bfos != null) 46 { 47 bfos.close(); 48 } 49 } 50 catch (IOException e) 51 { 52 e.printStackTrace(); 53 } 54 } 55 }
19天-15-IO流读取键盘录入
System.out: 对应的是标准输出设备,控制台。
System.in: 对应的标准输入设备,键盘。
流操作键盘录入示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * 键盘录入,over表示结束 3 */ 4 public static void keyboardEntry() throws IOException 5 { 6 BufferedReader br = null; 7 BufferedWriter bw = null; 8 try 9 { 10 br = new BufferedReader(new InputStreamReader(System.in)); 11 bw = new BufferedWriter(new OutputStreamWriter(System.out)); 12 String temp; 13 while ((temp = br.readLine()) != null) 14 { 15 if ("over".equals(temp)) 16 { 17 break; 18 } 19 bw.write(temp); 20 bw.newLine(); 21 bw.flush(); 22 } 23 } 24 finally 25 { 26 if (br != null) 27 { 28 br.close(); 29 } 30 if (bw != null) 31 { 32 bw.close(); 33 } 34 } 35 }
流操作的基本规律:
通过三方面来确定:
1.明确源和目的
源:输入流,InputStream,Reader
目的:输出流,OutputStream,Writer
2.操作的数据是否是纯文本
是:字符流 否:字节流
3.当体系明确后,再明确要使用哪个具体的对象。
通过设备来区分:源设备:内存,硬盘,键盘;目的设备:内存,硬盘,控制台
注:转换流:主要用于字节流与字符流的转换和在涉及字符编码时指定编码。
20天-01-IO流File类
File类:用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作,File对象可以作为参数传递给流的构造函数。
File类常用方法:
1.创建 boolean createNewFile();//在指定位置创建文件,如果该文件已经存在,则不创建文件返回false
boolean mkdir();//创建文件夹 boolean mkdirs();//创建多级文件夹
2.删除 boolean delete();//删除失败返回false void deleteOnExit();//在程序退出时删除指定文件
3.判断 exists();//文件是否存在 isHidden();//判断是否是隐藏文件 canExecute();//判断文件是否可执行
isFile();//是否是文件 isDirectory();//判断是否是目录 isAbsolute();//判断是否是绝对路径
注:在判断文件对象是否是文件或者目录时,必须要先判断文件对象封装的内容是否存在,通过exists()判断
4.获取 getName();//获取文件名 getPath();//获取文件封装路径 getParent();//获取文件封装父目录
getAbsolutePath();//获取文件绝对路径 lastModified();//获取文件最后修改时间 length();//获取文件大小
删除文件操作示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * 递归遍历删除所有文件 3 * 4 * @param file 文件路径 5 */ 6 public static void deleteFile(File file) 7 { 8 if (!file.exists()) 9 { 10 return; 11 } 12 File[] fileList = file.listFiles(); 13 for (File f : fileList) 14 { 15 if (f.isDirectory()) 16 { 17 deleteFile(f); 18 } 19 else 20 { 21 f.delete(); 22 } 23 } 24 file.delete(); 25 }
20天-11-IO流Properties类
Properties是hashtable的子类,也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串,是集合和IO技术相结合的集合容器。在加载数据时,需要数据有固定的格式:键=值
打印流:该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节流打印流:PrintStream 构造函数可以接收的参数类型:
1.file对象,File;2.字符串路径,String;3.字节输出流,OutputStream
字符打印流:PrintWriter 构造函数可以接收的参数类型:
1.file对象,File;2.字符串路径,String;3.字节输出流,OutputStream;4.字符输出流,Writer
序列流SequenceInputStream:将多个数据源的文件流合并到一起。
文件合并流示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 * 把多个文件里面的数据合并到一个文件里面 3 * 4 * @param targetFile 合入文件 5 * @param sourceFiles 多个原文件 6 * @throws IOException 7 */ 8 public static void combineTFiles(String targetFile, String... sourceFiles) 9 throws IOException 10 { 11 ArrayList<FileInputStream> v = new ArrayList<FileInputStream>(); 12 for (String s : sourceFiles) 13 { 14 v.add(new FileInputStream(s)); 15 } 16 Iterator<FileInputStream> it = v.iterator(); 17 Enumeration<FileInputStream> en = new Enumeration<FileInputStream>() 18 { 19 @Override 20 public boolean hasMoreElements() 21 { 22 return it.hasNext(); 23 } 24 25 @Override 26 public FileInputStream nextElement() 27 { 28 return it.next(); 29 } 30 }; 31 SequenceInputStream sis = new SequenceInputStream(en); 32 FileOutputStream fos = new FileOutputStream(targetFile); 33 byte[] bf = new byte[1024]; 34 int length = 0; 35 while ((length = sis.read(bf)) != -1) 36 { 37 fos.write(bf, 0, length); 38 } 39 sis.close(); 40 fos.close(); 41 }
对象流ObjectInputStream,ObjectOutputStream:被操作的对象需要实现Serializable(标记接口),对象中的transient和static修饰的成员变量不会被读取和写入
实现Serializable接口的类,需要做一个标记方便后期修改 static final long serialVersionUID = 10L;
管道流PipedInputStream,PipedOutputStream:输入输出可以直接进行连接,通过结合多线程使用,先把数据写入管道再从管道里面读取出来。
管道流示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Demo 2 { 3 public static void main(String[] args) 4 { 5 //exit为退出管道示例命令 6 PipedInputStream pis = new PipedInputStream(); 7 PipedOutputStream pos = new PipedOutputStream(); 8 //读取管道流连接写入管道流,当有数据写入管道时,读取管道线程自动读入数据 9 pis.connect(pos); 10 new Thread(new ReadPiped(pis)).start(); 11 new Thread(new WritePiped(pos, System.in)).start(); 12 } 13 } 14 class ReadPiped implements Runnable 15 { 16 private PipedInputStream in; 17 public ReadPiped(PipedInputStream in) 18 { 19 this.in = in; 20 } 21 @Override 22 public void run() 23 { 24 try 25 { 26 byte[] bt = new byte[1024]; 27 int len = 0; 28 while (true) 29 { 30 len = in.read(bt); 31 String str = new String(bt, 0, len); 32 if ("exit".equals(str)) 33 { 34 break; 35 } 36 System.out.println(str); 37 } 38 in.close(); 39 } 40 catch (IOException e) 41 { 42 e.printStackTrace(); 43 } 44 } 45 } 46 class WritePiped implements Runnable 47 { 48 private PipedOutputStream out; 49 private BufferedReader bf = null; 50 public WritePiped(PipedOutputStream out, InputStream in) 51 { 52 this.out = out; 53 bf = new BufferedReader(new InputStreamReader(in)); 54 } 55 @Override 56 public void run() 57 { 58 try 59 { 60 String temp; 61 while (true) 62 { 63 temp = bf.readLine(); 64 out.write(temp.getBytes()); 65 if ("exit".equals(temp)) 66 { 67 break; 68 } 69 } 70 bf.close(); 71 out.close(); 72 } 73 catch (IOException e) 74 { 75 e.printStackTrace(); 76 } 77 } 78 }
随机访问文件RandomAccessFile:该类不算IO体系中的子类,而是直接继承自Object。但是它是IO包中成员,因为它具备读和写功能,内部封装了一个数组,而且通过指针对数组的元素进行操作,可以通过getFilePointer获取指针位置,同时也可以通过seek修改指针的位置。其实内部完成读写的原理是内部封装了字节输入流和输出流。
如果模式为只读 r,不会创建文件,会去读取一个已存在的文件,如果文件不存在,则会抛异常。
如果模式为读写 rw,操作的文件不存在,会自动创建,如果文件存在则不会覆盖。
特点:可以随机的读写文件里面的数据,用于多线程把数据分段存到一个文件里(多线程下载)。
void seek(long pos); //设置指针位置,方便修改指定位置数据
int skipBytes(int n); //指针向前跳n个字节,不能向后跳
基本数据类型流DataInputStream,DataOutputStream:可以用于操作基本数据类型的数据的流对象
字节数组流
ByteArrayInputStrean:在构造函数里,需要接收数据源,而且数据源是一个字节数组
ByteArrayOutputStream:在构造函数里,不用定义数据目的,该对象内部已经封装了可变长度的字节数组,就是数据目的地。
因为这两个流对象都操作的数组,并没有使用系统资源。所以不用进行close关闭。
void writeTo(OutputStream out); //把数组里面的数据写入流里面
字符数组流 CharArrayReader,CharArrayWriter
字符串流 StringReader,StringWriter
21天-07-字符编码
ASCII:美国标准信息交换码,用一个字节的7位可以表示
ISO8859-1:拉丁码表,欧洲码表,用一个字节的8位表示
GB2312:中国的中文编码表
GBK:中国的中文编码表升级,融合了更多的中文文字字符,用两个字节的8位表示,每个字节前面第一位是标识
Unicode:国际标准码,融合了多种文字,所有文字都用两个字节来表示,Java语言使用的就是Unicode
UTF-8:最多用三个字节来表示一个字符
编码:字符串变成字节数组
String-->byte[]; str.getBytes(charsetName);
解码:字节数组变成字符串
byte[]-->String; new String(byte[],charsetName);
编码转换示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import java.io.IOException; 2 import java.io.UnsupportedEncodingException; 3 class Demo 4 { 5 public static void main(String[] args)throws IOException 6 { 7 encodeShow("test", "gbk"); 8 encodeShow("test", "utf-8"); 9 encodeShow("test", "GB2312"); 10 encodeShow("test", "ascii"); 11 encodeShow("test", "unicode"); 12 encodeShow("test", "ISO8859-1"); 13 } 14 public static void encodeShow(String param, String charset) 15 throws UnsupportedEncodingException 16 { 17 String str = param; 18 sop("source string: " + str + " encode is: " + charset); 19 byte[] bt = str.getBytes(charset); 20 for (byte b : bt) 21 { 22 sop("encode binary: " + Integer.toBinaryString(b)); 23 } 24 String t = new String(bt, charset); 25 sop("encode string: " + t); 26 sop(""); 27 } 28 private static void sop(Object obj) 29 { 30 System.out.println(obj); 31 } 32 }
换行符: Linux:\n windows:\r\n Mac:\r