黑马程序员——方法总结之IO

------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

/*
1.File
	File是文件和目录的抽象表示形式
	构造方法
		File(String pathname);根据一个路径得到File对象
		File(String parent,String child);根据一个目录和一个子目录/文件得到一个File对象
		File(File parent,String child);根据一个父File对象和一个子目录/文件得到一个File对象
	主要功能:
		创建功能
			public boolean creatNewFile();创建文件,如果已经存在就会创建失败
			public boolean mkdir();创建目录,如果已近存在就会创建失败
			public boolean mkdirs();创建目录,如果父目录不存在会自动创建
		删除功能
			public boolean delete();删除目录或文件,入股目录中存在内容则删除失败
		重命名
			public boolean renameTo(File dest);
			如果路径相同就是改名,如果不同就是移动,如果目标位置有同名文件/目录则修改失败。
		判断功能
			public boolean isDirectory();判断是否是目录
			public boolean isFile();判断是否是文件
			public boolean exists();判断是否存在
		获取功能
			public Stirng getAbsolutePath();获取绝对路径
			public String getPath();获取相对路径
			public String getName();获取名称
			public long length();获取文件/目录字节大小
			public long lastModified();获取最后一次修改的时间,毫秒值
		特殊获取功能
			public String[] list();获取指定目录下所有文件和文件夹的名称数组
			publlic File[] listFiles();获取指定目录下所有文件和目录的File数组
			
			利用文件名过滤器获取符合要求的数组
			public String[] list(FilenameFilter filter);
			public File[] listFiles(FilenameFilter filter);
			如:获取指定目录下后缀名为.jpg的文件
				//封装目录
				File file  = new File("e:\\");
				//通过文件名过滤器获取符合要求的文件
				String[] strArray = file.list(new FilenameFilter(){
					public boolean accept(File dir,String name){		
					//这里的dir指的是被判断的目录,name指的是目录下的各个文件和目录的名称
						return new File(dir,name).isFile() && name.endswith(".jpg");
					}
				});
			
2.FileOutputStream 字节输出流对象
	构造方法
		FileOutputStream(File file);
		FileOutputStream(String name);——常用
	写入方法
		public void write(int b);写一个字节
		public void write(byte[] b);写一个字节数组
		public void write(byte[] b,int off,int len);写一个字节数组的一部分
		
		两个小问题:
			如何换行:write("\r\n".getBytes());
				windows:\r\n
				linux:\n
				Mac:\r
			如何追加写入:用构造方法带第二个参数是true的情况即可
				FileOutputStream(File f,boolean flag);
3.FileInputStream 字节输入流对象
	构造方法相同
	读取方法:
		public int read();
		public int read(byte[] b);
		举例:
			一次读取一个字节
			int by = 0;
			while((by = fis.read())!=-1){
				Syetem.out.println((char) by);
			}
			一次读取一个字节数组
			byte[] bys = new byte[1024];
			int len;
			while((len = fis.read(bys))!=-1){
				System.out.println(new String(bys,0,len));
			}
	一个小问题:计算机是如何识别什么时候把两个字节转换为一个中文字的呢?
		在计算机中中文的存储分两个字节:
				第一个字节肯定是负数。
				第二个字节常见的是负数,可能有正数。但是没影响。
		
4.字节缓冲区类
	写数据:BufferedOutputStream(OutputStream out);
	读数据:BufferedInputStream(InputStream in);
	字节缓冲区流仅仅提供缓冲区,为高效而设计的。但是呢,真正的读写操作还得靠基本的流对象实现。
	所以需要传递一个OutputStream对象做参数。实际传递的是其子类实例。
	
5.转换流(把字节流转换为字符流)
	写数据:
		OutputStreamWriter(OutputStream out);根据默认编码转换字节流数据为字符流
		OutputStreamWriter(OutputStream out,String charsetName);使用指定编码把字节流数据转换为字符流
	读数据:
		InputStreamReader(InputStream is);用默认编码读取数据
		InputStreamReader(InputStream is,String charsetName);使用指定编码读取数据
	字符流=字节流+编码表;默认使用GBK编码表,一般都是用默认。
	
	InputStreamReader的方法:
		int read();一次读取一个字符
		int read(char[] chs);一次读取一个字符数组
		实例:
			int ch = 0 ;
			while((ch=isr.read())!=-1){
				System.out.println((char) ch);
			}
			char[] chs = new char[1024];
			int len = 0;
			while((len = isr.read())!=-1){
				System.out.println(new String(chs,0,len));
			}
		
	OutputSreamWriter的方法
		public void write(int c);写一个字符
		public void write(char[] chs);写一个字符数组
		public void write(char[] chs,int off,int len);写一个字符数组的一部分
		public void write(String str);写一个字符串
		public void write(String str,int off,int len);写一个字符串的一部分
	一个小问题:字符流的写入必须刷新后数据才可以被写入。在执行close操作时也有刷新缓冲区操作。
	
	转换流的名称有点长,所以,Java就提供了其子类供我们使用。可以直接传递文件名做参数
	FileWriter(String name);
	FileReader(String name);
			
6.字符缓冲区流/字符高效流
	写入流:
	BufferedWriter(Writer out);
		特殊方法
			public void Write(String str);一次写入一个字符串
			public void newLine();写入换行符,根据系统来决定写入的换行符
	BufferedReader(Reader in);
		特殊方法
			public String readLine();一次读取一行数据,包含数据不包含终止符,如果到达流末位,返回null
	
	一个特殊类:LineNumberReader是BufferedReader的子类
		特有方法:
			public int getLineNumber();获得当前行号
			public void setLineNumber(int lineNumber);设置行号
			
7.其他常用流
	1).打印流
		PrintStream
		PrintWriter
		特殊功能:
			可以直接传递文本文件,也可以传递其他流;
			只能写数据,不能读数据;
			可以操作任意类型的数据;
			启动自动刷新后可以自动刷新,但只限特殊构造方法可用,且仅限println()方法可以自动刷新;
			public PrintStream(OutputStream out,boolean autoFlush);
			public PrintWriter(OutputStream out,boolean autoFlush);
			public PrintWriter(Writer out,boolean autoFlush);
		主要方法:
			print();
			println();
			这两个方法中的参数可以是任意基本类型和String类型。
			具体来说:boolean/char/char[]/double/float/int/long/object/string
			当启用了自动刷新时,该类的println()方法就相当于是BufferedReader的
			write();	newLine();	flush();		三个方法的效果。
			实例:
				String line = null;
				while((line=br.readLine())!=null){
					pw.println(line);
				}
			
	2).标准输入输出流
		System类中的两个成员变量:
			public static final InputStream in “标准”输入流。
			public static final PrintStream out “标准”输出流。
			由此可见,标准输出流其实是打印流对象;标准输入流是字节输入流对象。
			InputStream is = System.in;
			PrintStream ps = System.out;
		标准输入流:System.in		InputStream is = System.in;
		此流是字节输入流,只能按字节读取键盘数据,
		在jdk1.5之前包装此流用来接收键盘录入整行数据
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			System.out.println("请输入一个字符串:");
			String line = br.readLine();
		且可以把读取到的字符串装换为需要的数据类型,如:
			System.out.println("请输入一个整数:");
			line = br.readLine();
			int i = Integer.parseInt(line);
			
	3).随机访问流RandomAccessFile
		该类不算是IO体系中的子类,而是直接继承自Object类,但它又是IO包中的成员
		因为它同时具备读和写的功能。
		其内部封装了一个数组,而且通过指针对数组的元素进行操作。
		构造方法:
			RandomAccessFile(File file, String mode)
			RandomAccessFile(String name, String mode) 
			常用模式是只读r和读写rw,模式对应功能,只读模式是不能写入数据的。
		常用方法:
			该类的方法中,有读取一行数据的方法readLine();但却没有写入字符串的方法。
			String readLine();
			int read()
			int read(byte[] b)
			int read(byte[] b, int off, int len)
			boolean readBoolean()			readByte/Char/Double/Float/Int/Long/Short
			write(int b)
			write(byte[] b)
			write(byte[] b, int off, int len)		writeBoolean/Byte/Char/Double/Float/Long/Short
		特殊用法:
			使用writeInt()和readInt()方法与seek()和skipBytes()方法配合可以在文件中随机的写入和读取。
			一次写入4个字节;一次读取4个字节;设置指针位置;
			实例:
				写数据:
					raf.write("李四".getBytes());//一个汉字两个字节,写入了4个字节
					raf.writeInt(97);					//97虽然只占一个字节,但是writeInt写入了4个字节
					raf.write("王五".getBytes());
					raf.writeInt(99);
				读数据:
					raf.skipBytes(8);//跳过指定的字节数
					//raf.seek(8*1);	也可以使用此方法来调整指针的位置
					byte[] buf = new byte[4];//一次读取4个字节的数组
					raf.read(buf);		//每读取一次,指针做对应偏移
					String name = new String(buf);
					int age = raf.readInt();	//读取4个字节
					System.out.println("name="+name);//王五
					System.out.println("age="+age);//99
		
	4).序列化流
		ObjectOutputStream	序列化:		对象——数据流
		ObjectInputStream		反序列化:	数据流——对象(即读取数据的结果是创建了一个对象)
		构造方法:
			ObjectInputStream(InputStream in)
			ObjectOutputStream(OutputStream out)
		特有方法:
			该类肯定具备了父类的所有方法,既然是序列化流,肯定提供了特殊的方法。
			readObject(Object obj)	还原对象
			writeObject(Object obj)	把对象写入文本(其实写入的是地址值)
		实例:
			序列化:
				ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
				Person p = new Person("tony",28);
				oos.writeObject(p);
				oos.close();
			反序列化:
				ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txxt"));
				Object obj = ois.readObject();
				ois.close();
		注意事项:
			A:被序列化的对象需要实现Serializable接口
			B:为了防止出现InvalidClassException异常,要自动生成一个序列化id值,也可以手写。
				private static final long serialVersionUID = -2071565876962058344L;
			C:可以使用transient关键字声明不需要序列化的成员变量。
				private transient int age;
				
	5).合并流SequenceInputStream
		该流提供了特殊的构造方法,可以使用其他的字节流对象创建该类的对象,可以一次读取
		所有对象的数据,所以可以实现合并。所以该流只提供读取流。
		A:合并两个文件SequenceInputStream(InputStream s1, InputStream s2)
				InputStream s1 = new FileInputStream("ByteArrayStreamDemo.java");
				InputStream s2 = new FileInputStream("DataStreamDemo.java");
				SequenceInputStream sis = new SequenceInputStream(s1, s2);
		B:合并多个文件SequenceInputStream(Enumeration e)
			Enumeration是枚举接口也是Vector中的一个方法的返回值类型Enumeration elements()
			即通过把对象存入Vector集合,然后把其中包装的文件传递给该类的对象实现合并
				Vector v = new Vector();
				InputStream s1 = new FileInputStream("ByteArrayStreamDemo.java");
				InputStream s2 = new FileInputStream("CopyFileDemo.java");
				InputStream s3 = new FileInputStream("DataStreamDemo.java");
				v.add(s1);
				v.add(s2);
				v.add(s3);
				Enumeration en = v.elements();
				SequenceInputStream sis = new SequenceInputStream(en);
			但是,这样做并不是太好,因为Vector集合的效率较低,那么怎么改进呢?
			通过ArrayList改进:把对象存入集合——获取集合的迭代器——通过迭代器创建枚举对象
				ArrayList al = new ArrayList();
				al.add(s1);
				al.add(s2);
				al.add(s3);
				final Iterator it = la.iterator();	//匿名内部类访问的成员变量需要使用final修饰
				//通过匿名内部类实例化接口对象
				Enumeration en = new Enumeration(){
					//重写接口的抽象方法
					public boolean hasMoreElements()
					{
						return it.hasNext();
					}
					public FileInputStream nextElement()
					{
						return it.next();
					}
				};
				SequenceInputStream sis = new SequenceInputStream(en);
		C:既然可以合并,那么如何拆分文件呢????
			思路是这样的:
				A:先用输入流封装(关联)要被拆分的文件
				B:因为要拆分为多个文件,所以目标对象不能马上封装
					确定拆分后的每个文件的大小,据此来决定每次读取多大的文件
					每读取一次,用输出流封装一个目标对象,然后读取的数据写入文本
					实现文件拆分
			实现:
				FileInputStream fis = new FileInputStream("c:\\1.bmp");
				FileOutputStream fos = null;
				byte[] bys = new byte[1024*1024];		//切割文件大小为1M
				int len = 0;
				int count=1;
				while((len=fis.read(bys))!=-1){
					fos = new FileOutputStream("c:\\splitfiles\\"+(count++)+".part");
					fos.write(bys,0,len);
					fos.close();
				}
	6).内存操作流
			用于处理临时存储信息的,程序结束,数据就从内存中消失
			即数据的读取和写入都是操作的内存,而不是文件。
		构造方法
			ByteArrayOutputStream() 
			ByteArrayInputStream(byte[] buf)
			
			CharArrayWriter() 
			CharArrayReader(char[] buf) 
			
			StringWriter() 
			StringReader(String s) 
			
			可以发现:写入时不用传入参数,读取时传入对应的数据类型。
			读取的数据也就是通过输入流的特殊方法获取的,对应方法为:
			public byte[] toByteArray()
			public char[] toCharArray()
			public String toString()
		实例:
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			for (int x = 0; x < 10; x++) {
				baos.write(("hello" + x).getBytes());
			}
			// 通过查看源码我们知道这里什么都没做,所以根本需要close()
			byte[] bys = baos.toByteArray();
			// 读数据
			// ByteArrayInputStream(byte[] buf)
			ByteArrayInputStream bais = new ByteArrayInputStream(bys);
			int by = 0;
			while ((by = bais.read()) != -1) {
				System.out.print((char) by);
			}
		特殊说明:
			由于内存操作流,并没有调用系统的资源,所以不用close。
			
	7).数据操作流
			可以读写基本数据类型的数据,很少使用。
		构造方法:
			 * 数据输入流:DataInputStream(InputStream in)
			 * 数据输出流:DataOutputStream(OutputStream out)
		// 写数据了
			dos.writeByte(10);
			dos.writeShort(100);
			dos.writeInt(1000);
			dos.writeLong(10000);
			dos.writeFloat(12.34F);
			dos.writeDouble(12.56);
			dos.writeChar('a');
			dos.writeBoolean(true);
		// 读数据
			byte b = dis.readByte();
			short s = dis.readShort();
			int i = dis.readInt();
			long l = dis.readLong();
			float f = dis.readFloat();
			double d = dis.readDouble();
			char c = dis.readChar();
			boolean bb = dis.readBoolean();
8.与流有关的特殊类Properties
		是Hashtable的子类,但是限制了只能存储String类型的键和值,所以不需使用泛型。
		既然是map集合的一员,肯定具备了map集合的所有功能。
	特殊功能:
		public Object setProperty(String key,String value):添加元素
		public String getProperty(String key):获取元素
		public Set stringPropertyNames():获取所有的键的集合
	特有功能:
		把文件中的数据读取到集合中
		public void load(Reader reader);
		把集合中的数据存储到文件,并给文件加上注释
		public void store(Writer writer,String comments);
	实例:
		加载文件:
			Properties prop = new Properties();
			// 注意:这个文件的数据必须是键值对形式
			Reader r = new FileReader("prop.txt");
			prop.load(r);
			r.close();
		上传数据:
			Properties prop = new Properties();
			prop.setProperty("林青霞", "27");
			prop.setProperty("武鑫", "30");
			prop.setProperty("刘晓曲", "18");
			//public void store(Writer writer,String comments):把集合中的数据存储到文件
			Writer w = new FileWriter("name.txt");
			prop.store(w, "helloworld");
			w.close();
*/



你可能感兴趣的:(java基础)