Java基础(20,21)IO流

二十八.IO流列出目录下所有内容-递归


import java.io.*;
class IoTextDemo
{
	public static void main(String[] args)
	{
		//开始名字写错了,返回null
		File dir = new File("E:\\JAVA_TEXT"); //System.out.println(dir);//打印的是E:\\JAVA_TEST
		
		
		
		//System.out.println(dir);
		showDir(dir,0);
	}
	public static String getLevel(int level)
	{
		StringBuilder sb = new StringBuilder();
		
		sb.append("|--");
		for(int i = 0;i<level;i++)
		{
			sb.insert(0 ,"|  ");
		}
		return sb.toString();
	
	}

	public static void showDir(File dir,int level)
	{
		
		System.out.println(getLevel(level)+dir.getName());
		level++;

		File[] filelist =dir.listFiles();
		
		//System.out.println(dir);//显示主目录的名字
		for(int i = 0;i<filelist.length;i++)
		{
			
			if(filelist[i].isDirectory())//如果读到的是一个目录,就继续往里面读
			{
				showDir(filelist[i],level);
			}
			else //不是目录是文件
			{
				

				System.out.println(filelist[i]);//这个地方不写层级,
				//只有目录会有| ,文件前面没有
				//System.out.println(getLevel(level)+filelist[i]);
			}
		
		
		
		}


	
	
	}
}

二十九.IO流删除带内容的目录

删除原理:
在window中,删除目录从里面往外删除的。
既然从里往外删除。就需要用到递归

import java.io.*;

class IoTextDemo
{
	public static void main(String[] args)
	{
		File dir = new File("E:\\JAVA_TEXT");
		
		removeDir(dir);
		


	
	}

	public static void removeDir(File dir)
	{
		File[] files = dir.listFiles();
		
		for(int i = 0;i<files.length;i++)
		{
			if(files[i].isDirectory())
			{
			
				removeDir(files[i]);//如果是目录继续往里走,看看是不是目录,知道找到文件然后删除
			}
			else
			{
				//如果打印false ,就说明一个文件夹被删了两次
				System.out.println(files[i].toString()+"-file-"+files[i].delete());
			}
		}

		System.out.println(dir+"::"+dir.delete());//删除文件
		
	
	}
}

三十.IO流创建java文件列表,   前面有一个用listFile做的,可以对比一下

练习
将一个指定目录下的java文件的绝对路径,存储到一个文本文件中。
建立一个Java文件列表文件。


思路:
1.对指定的目录进行递归。
2.获取递归过程所有的java文件的路径
3.将这些路径存储到集合中,存入list!!!!
4.将集合中的数据写入到一个文件中

import java.io.*;
import java.util.*;
class IoTextDemo
{
	public static void main(String[] args) 
	{
		File dir = new File("E:\\JAVA_TEXT");
		//FileWriter fw = new FileWriter("E:\\list_document.txt");
		File f = new File("E:\\list_java.txt");//看看f打印什么
		File f1 = new File("E:\\玩玩.txt");
		try
		{
			System.out.println(f);  //打印出E:\list_java.txt   //这个文件存在
			System.out.println(f1); //打印出E:\玩玩.txt  //这个文件并不存在
		}
		catch (Throwable e)
		{
			throw new RuntimeException("cuo");
		}
	

		ArrayList<File> alist = new ArrayList<File>();

		fileAddToList(dir,alist); //把文件信息存到集合中

		writeTofile(alist ,f.toString());  //从集合中把信息写到文件上
	
	
	}
	public static void fileAddToList(File dir ,ArrayList<File> list )
	{
	
		File[] files = dir.listFiles();


	//	高级for循环取数据
	//	for(File file : files)
	//	{
	//		if(file.isDirectory())
	//		{
	//			fileToList(file ,list);
	//		}
	//		else
	//		{
	//			if(file.getName().endsWith(“.java”))
	//			list.add(file);
	//		}

	//	}

		//传统for循环
		for(int i = 0;i<files.length;i++)
		{
			if(files[i].isDirectory()) //如果是目录就继续进去
			{
				fileAddToList(files[i],list)	;
			}
			else //如果是文件就添加进list集合
			{
				if(files[i].getName().endsWith("java"))
				list.add(files[i]);
				
			}
		
		
		}
	
	}
	public static void writeTofile(ArrayList<File> list , String file)
	{
		
		FileWriter fw = null;
		BufferedWriter bufw = null;
		try
		{
			fw = new FileWriter(file);
			bufw = new BufferedWriter(fw);

		//	高级for循环取出数据
		//	for(File f:list)
		//	{
		//	String path = f.getAbsolutePath();
		//	bufw.write(path);
		//	bufw.newLine();
		//	bufw.flush();
		//	}

			//用迭代器取出数据
			Iterator<File> it = list.iterator();  //这里开始写错了
			while(it.hasNext())
			{
				File fi = it.next();
				String filepath = fi.getAbsolutePath();
				bufw.write(filepath);
				bufw.newLine();
				bufw.flush();
			
			}
		}
		catch (Throwable e)
		{
			throw new RuntimeException("错误1");
		}
		finally
		{
			try
			{
				if(bufw !=null)
				{
					bufw.close();
				}
			}
			catch (Throwable e)
			{
				throw new RuntimeException("错误2");
			}
			
		
		
		}
	
	

		
	
	
	
	}
}


三十一.IO流Properties

//properties是hashtable的子类
//也就是说它具备map集合的特点。而且它里面存储的键值对都是字符串。
//是集合中和IO技术相结合的结合容器。
//该对象的特点:可以用于键值对形式的配置文件。
//那么在加载数据时,需要数据有固定的格式,通常键 = 值。


import java.io.*;
import java.util.*;

class IoTextDemo
{
	public static void main(String[] args) throws IOException
	{
		
		//setAndGet();
		method_1();
	}

	public static void setAndGet()
	{
		Properties prop = new Properties();
		//setProperty(String key, String value),调用Hashtable的put方法
		prop.setProperty("zhangsan","30");
		prop.setProperty("lisi","39");
		
		System.out.println(prop);
		//stringPropertyNames()返回此属性列表中的键集,
		//其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,
		//则还包括默认属性列表中不同的键。
		String value = prop.getProperty("lisi");
		System.out.println(value);

		Set<String> names = prop.stringPropertyNames();

		prop.setProperty("lisi",89+"");//改变元素的值//改变值
		for(String  s : names)
		{
			System.out.println(s+":"+prop.getProperty(s)); //获取key
		}
	
	}
		
	//代码2
	//演示,如何将流中的数据存储到集合中。
	//想要将info.txt中键值数据存到集合中进行操作。
	//1.用一个流和info.txt文件关联。
	//2.读取一行数据,将该行数据用”=”进行切割。
	//3.等号左边作为键,右边作为值。存入到Properties集合中即可。
	public static void method_1() throws IOException
	{
	
		BufferedReader bufr = new BufferedReader(new FileReader("E:\\SYSTEM_INFO.txt"));
		String line = null;
		Properties prop = new Properties();
			while((line = bufr.readLine()) != null)
			{
				String[] arr = line.split("=");
				System.out.println(arr[0]+"---"+arr[1]);
				prop.setProperty(arr[0],arr[1]);
			
			
			}
			bufr.close();
			System.out.println(prop);
	
		
		
		
	
	
	
	}


	///代码3(优化代码2)
	public static void loadDemo() throws IOException //跟下面的功能一样,只是更简单了
	{
		Properties prop = new Properties();
		FileInputStream fis = new FileInputStream(“info.txt”);
		//将流中的数据加载进集合。从输入流中读取属性列表(键和元素对)。
		prop.load(fis);
		//System.out.println(prop);//和下面的效果一样 把键和值成对打印
		//prop.list(System.out);//和上面的效果一样
		//之前是99,这里改成39,打印出39,但是文件中还是99
		prop.setProperty(“wangwu”,”39”); / /只是改变了内存中值,源头没改变,如果要改变需要存起来
		//store是将内存中的数据(也就是上面的setProperty的数据)先存到流中,然后存到文件中,会打印时间
		FileOutputStream  fos = new FileOutputStream(“info.txt”);
		prop.store(fos.”haha”);//haha是注释

		fos.close();
		fis.close();
	}
}

三十二.IO流Properties练习

//用于记录应用程序运行次数。
//如果使用次数已到,那么给出注册提示。
//很容易想到的是:计数器
//可是该计数器定义在程序中,随着程序的运行而在内存中存在,并自行自增
//可是随着该应用程序的退出,该计数器也在内存中消失了。

//下一次在启动该程序,又重新开始从0计数。
//这样不是我们想要的。
//程序即时结束,该计数器的值也存在。
//下次程序启动时会先加载该计数器的值并加1后再重新存储起来。

//所以要建立一个配置文件。用于记录该软件的使用次数。

//该配置文件使用键值对的形式。
//这样便于阅读数据,并操作数据。

//键值对数据是map集合
//数据是以文件形式存储,使用io技术
//那么map+io-->properties

//配置文件可以实现应用程序数据的共享

import java.io.*;
import java.util.*;
class IoTextDemo
{
	public static void main(String[] args) throws IOException
	{
		File file = new File("E:\\count.txt");
		Properties pro = new Properties();
		
		if(!file.exists())
		{
		
			file.createNewFile(); //如果不存在就创建一个
		}
		FileInputStream fis = new FileInputStream(file);

		pro.load(fis);
		int count = 0;
		String value = pro.getProperty("time");
		if(value == null)
		{

			count++;
			pro.setProperty("time",count+"");	
		
		}
		else
		{
			count = Integer.parseInt(value); //如果没有这个,那么count每次进来都是0!!!
			count ++;
			pro.setProperty("time",count+"");
			if(count >4)
			{
			
				System.out.println("到期,请续费");
			}
		
		}
		FileOutputStream fos = new FileOutputStream(file); //改变了数据就要存到file文件中
		pro.store(fos,"");
		fos.close();
		fis.close();

	
	
	
	}
}

三十三.IO流printWriter

PrintWriter与PrintStream
可以直接操作输入流和文件
打印流:
该流提供了打印方法,可以将各种数据类型的数据都原样打印!!!

字节打印流:
PrintStream
构造函数可以接受的参数类型:
1.file对象。File
2.字符串路径。String
3.字节输出流。OutputStream(控制台对应的对象时是字节输出流)

字符打印流:
PrintWriter
构造函数可以接受的参数类型:
1file对象。File
2字符串路径。String
3字节输出流。OutputStream
4.字符输出流,Writer (跟上面的差别所在)

PrintWriter(OutputStream out , boolean auto Flush)
out - 输出流
autoFlush - boolean变量;如果为true ,则println,printf或format方法将刷新输出缓冲区

import java.io.*;

class IoTextDemo
{
	public static void main(String[] args) throws IOException
	{
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		
		//控制台输出
		//PrintWriter out = new PrintWriter(System.out , true);

		//如果把输出写入一个文件时,不能写true,因为针对的是流,才能自动刷新
		//PrintWriter out = new PrintWriter("E:\\20150405text2.txt");

		//把写入文件也弄成自动刷新
		//和上面的区别在于,输入完之后,不用over,文件就自动生成大写
		PrintWriter out = new PrintWriter(new FileWriter("E:\\20150405text4.txt"),true);

		String line = null;
		while((line = bufr.readLine()) != null)
		{
			if("over".equals(line))
			{
				break;
			}
			//如果new PrintWriter(System.out , true);不写true,那么输入小写之后不会立即显示写,因为在缓冲区中
			//没有刷新,over之后才会全部出来。如果有true,写一个对应的大写就出来了,自动刷新
			out.println(line.toUpperCase());

			
		}
		out.close();
		bufr.close();
	}
}

三十四.IO合并流

//把三个流放一起,然后再写在一个文件里(分别读取三个文件存到一个,要考虑续写问题,多个源对应一个目的)
//这里直接把多个源,变成一个源

import java.io.*;
import java.util.*;

class IoTextDemo
{
	public static void main(String[] args) throws IOException
	{
		Vector<FileInputStream> v = new Vector<FileInputStream>();
		v.add(new FileInputStream("E:\\hebing\\1.txt"));
		v.add(new FileInputStream("E:\\hebing\\2.txt"));
		v.add(new FileInputStream("E:\\hebing\\3.txt"));
		
		Enumeration<FileInputStream> en = v.elements();

		//SequenceInputStream(Enumeration<? extends InputStream> e) 
		//通过记住参数来初始化新创建的 SequenceInputStream,
		//该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。
		SequenceInputStream sis = new SequenceInputStream(en);
		FileOutputStream fos = new FileOutputStream("E:\\hebing\\4.txt");

		byte[] buf = new  byte[1024];
		int len = 0;
		
		//read(char[] cbuf)
		//public int read(byte[] b)
		//从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
		//在某些输入可用之前,此方法将阻塞。
		while((len = sis.read(buf)) != -1)
		{
			fos.write(buf,0,len);
		}
		fos.close();
		sis.close();
	
	}
}

三十五.IO流切割文件

import java.io.*;
import java.util.*;

class IoTextDemo
{
	public static void main(String[] args)throws IOException
	{
		
		//splitdocu();
		sequenceInput();
	
	}

	public static void splitdocu() throws IOException
	{
		FileInputStream fis = new FileInputStream("E:\\hebing\\w.jpeg");
		FileOutputStream fos = null;
	
		byte[] buf = new byte[1024*15];
		int len = 0;
		int count = 0;
		while((len = fis.read(buf)) != -1)
		{
			count++;
			fos = new FileOutputStream("E:\\hebing\\"+count+".jpeg");
			fos.write(buf,0,len);
		}
		fis.close();
		fos.close();
	
	}

	public static void sequenceInput()throws IOException
	{
	
		ArrayList<FileInputStream> list = new ArrayList<FileInputStream>();

		for(int i = 1;i<4;i++)
		{
			list.add(new FileInputStream("E:\\hebing\\"+i+".jpeg")); //会报错,FileInputStream 无法转为String
		}
	
		final Iterator<FileInputStream> it = list.iterator();

		//为什么要这么写,这个真不明白,因为只有Iterator有hasNext和next,Iterator跟Enumeration功能是一样的
		//方法摘要
		// boolean hasMoreElements()测试此枚举是否包含更多的元素
		// E nextElement()如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。
		Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()
		{	
			public boolean hasMoreElements()
			{
				return it.hasNext();
			}

			public FileInputStream nextElement()
			{
			
				return it.next();
			
			}

		};

		SequenceInputStream sis = new SequenceInputStream(en);

		FileOutputStream fos = new FileOutputStream("E:\\hebing\\f.jpeg");

		int len = 0;
		byte[]  buf = new byte[1024];
		while((len = sis.read(buf)) != -1)
		{
			fos.write(buf,0,len);
		}
		fos.close();
		sis.close();
	}
}

三十六.IO包中其他类

打印流
PrintWriter与PrintStream
可以直接操作输入流和文件

序列流
SequenceInputStream
对多个流进行合并

操作对象 ,也就把 堆内存中的对象存到文件中去 ,这个是他的重点!!!!! (硬盘),ObjectInputStream 与ObjectOutStream, 被操作的对象需要实现Serializable(标记接口)
ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久存储(即把对象存到文件中),ObjectInputStream 用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。

import java.io.*;

class IoTextDemo
{
	public static void main(String[] args) throws Exception
	{
		
		///writeObj();
		readObj();
	}
	public static void readObj() throws Exception
	{
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\hebing\\obj.txt"));
		Person p = (Person)ois.readObject();
		System.out.println(p);

		ois.close();
		
	}

	public static void writeObj() throws IOException
	{
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\hebing\\obj.txt"));
		//oos.writeObject(new Person("lisi",39));


		//按理说new person(“lisi”,39)是应该在堆内存当中,这里就都存在对象当中,
		//想把对象写在硬盘上(文件中)(用方法writeObject)
		oos.writeObject(new Person("lisi",39,"kr"));//lisi:39:cn//只能把堆里面的序列化,
		//不能把方法区里面的序列化
													
		oos.close();
	}
}

三十七.IO流RandomAccessFile

RandomAccessFile,该类不算是IO体系种子类,而是直接继承自Object。

但是它是 IO包中成员。因为它具备读和写功能,内部封装一个数组,而且通过指针对数组的元素进行操作,可以通过getFilePointer获取指针位置。
同时可以通过 seek改变指针的位置

其实完成读写的原理就是内部封装了字节输入流和输出流。
通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式,只读R,读写rw等。

如果模式为只读r,不会创建文件,会去读取一个已存在文件, 如果该文件不存在,则会出现异常(R), 而且该对象的构造函数要操作的文件不存在,会自动创建,如果存在则不会覆盖(W)

RandomAccessFile, 随机访问文件,自身具备读写的方法。通过skipBytes(int x),seek(int x)来达到随机访问。!!!!!这个是他的优点.

import java.io.*;

class IoTextDemo
{
	public static void main(String[] args) throws Exception
	{
		//writeFile();
		//readFile();
		writeFile_2();
	}

	public static void writeFile() throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("E:\\hebing\\ran1.txt","rw");

		raf.write("王五".getBytes());//一个中文2个字节
		//raf.write(97);//raf.write只写最低8位,如果超过就不能正确打印比如258,
						//但是可以用WriteInt();
						//文件中是王五a,读四个字节//因为记事本回去查GBK
		raf.writeInt(97);//文件中是王五   a,中间有3个空格!!!(不是空格,应该是换行符,如果是空格,我自己写的三个空格,等会读年龄的时候读不出来)
		
		raf.write("赵四".getBytes());
		raf.writeInt(22);
		
		raf.close();
	
	
	
	}

	public static void readFile() throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("E:\\hebing\\ran1.txt","r");
		
		//之前打印
		//name=王五
		//age=97
		//调整对象中指针   前后都可以
		//raf.skipBytes(8); //跟下面效果一样,只是只能往前走不能往后走!!!!!
		raf.seek(8);//相当于从第八个字节开始读  一个中文2个字节,int四个字节
					//现在打印
					//name=赵四
					//age=22
					


		byte[] buf =new byte[4];
		raf.read(buf);
		String name = new String(buf);
		int age = raf.readInt();

		System.out.println("name="+name);
		System.out.println("age="+age);

		raf.close();
	
	
	
	}
	//可以中间不写,直接写第四个,,或者修改之前写过的,在平常下载的时候,
	//每一段数据都是单独一个线程进行写,这样就要求数据有规律,比如录入户口,16个字节写名字,四个字节写年龄
	//20个字节是一个人,所以这样就可以分段读写
	//如果是一般流,只能从头写到尾,只是多个线程从头写到位,那么数据不是按顺序来的,
	//解码会报错(如下图)
	public static void writeFile_2()throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("E:\\hebing\\ran1.txt","rw");
		raf.seek(8*5);//从第四十个字节开始写

		raf.write("周期".getBytes());
		raf.writeInt(103);
		raf.close();
	
	}
}

三十八.IO流中的管道流

管道流
PopedinputStream 和PipedOutStream
输入输出可以直接进行连接,通过结合教程使用。
管道输入流应该连接到管道输出流;
管道输入流提供要写入管道输出流的所有数据字节。通常,
数据由某个线程从 PipedInputStream 对象读取,
并由其他线程将其写入到相应的 PipedOutputStream。
不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。

import java.io.*;

class IoTextDemo
{
	public static void main(String[] args) throws IOException
	{
		PipedInputStream in = new PipedInputStream();
		PipedOutputStream out = new PipedOutputStream ();
		in.connect(out);
		Read r = new Read(in);
		Write w = new Write(out);
		new Thread(r).start();
		new Thread(w).start();
	}
}

class Read implements Runnable 
{
	private PipedInputStream in;

	Read(PipedInputStream in)
	{
	
		this.in = in;
	}
	public void run()
	{		
		
		
		try
		{
			System.out.println("读取钱。。。没有数据就阻塞");
			byte[] buf = new byte[1024];
			int len = in.read(buf);// //阻塞式方法读取数据(如果没有数据就停在这,这时候其他线程就获取执行权)
			System.out.println("读到数据,阻塞结束");

			String s = new String(buf,0,len);
			System.out.println(s);
			in.close();
		}
		catch (IOException e)
		{
			throw new RuntimeException("管道读取失败");
		}
		
//		  这种方法虽然OK,但是不适合代码原理展示
//		PrintStream ps = new PrintStream(System.out);
//		int line = 0;
//		try
//		{		//0-255的ASKII值
//				while((line = in.read()) !=  -1)
//				{
//				
//					ps.println((char)line);
//				}
//				in.close();
//				ps.close();
//		}
//		catch (IOException e)
//		{
//			throw new RuntimeException("管道读取流失败");
//		}
		
	
	
	}

}

class Write implements Runnable
{
	private PipedOutputStream out;

	Write(PipedOutputStream out)
	{
	
		this.out = out;
	}

	public void run()
	{
		try
		{
			System.out.println("开始写入数据,等待6秒");
			Thread.sleep(6000);
			out.write("da wang jiao wo lai xun shang".getBytes());
			out.close();
		}
		catch (Exception e)
		{
			throw new RuntimeException("管道输出流失败");
		}
		
	
	}
}


三十九.IO流操作基本数据类型的流对象DataStream

重点在于:可以用于操作基本数据类型的数据的流对象,把基本数据和流结合起来!!!!

import java.io.*;


class IoTextDemo
{
	public static void main(String[] args)throws IOException
	{
		//writeData();
		readData();
	
	}
	public static void writeData()throws IOException
	{
	
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("E:\\hebing\\data.txt"));
		dos.writeInt(234);
		dos.writeBoolean(true);
		dos.writeDouble(9887.543);

		dos.close();
	
	}

	public static void readData()throws IOException
	{
		//必须按照写的顺序读
		DataInputStream dis = new DataInputStream(new FileInputStream("E:\\hebing\\data.txt"));
		int num = dis.readInt();
		boolean b =dis.readBoolean();
		double d = dis.readDouble();

		System.out.println("num="+num);
		System.out.println("b="+b);
		System.out.println("d="+d);
		dis.close();
	
	}
	//以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。
	public static void writeUTFDemo()throws IOException
	{
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("E:\\hebing\\data.txt"));
		dos.writeUTF("你好");//用什么编码写就必须要用什么编码读
		dos.close();
	}

	public static void readUTFDemo()throws IOException
	{
		DataInputStream dis = new DataInputStream(new FileInputStream("E:\\hebing\\data.txt"));
		
		String s = dis.readUTF();
		System.out.println(s);
		dis.close();
	}
}

四十.用于操作字节数组的流对象

ByteArrayInputStream:在构造的时候,需要接受数据源,而且数据源是一个字节数组。
ByteArrayOutputStream : 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数据,这就是数据的目的地( 这就是他的重点 )
下面这几个原理都是一样的
*************************************************
操作字节数组
ByteArrayInputStream与ByteArrayOutputStream
操作字符数据
CharArrayReader与CharArrayWrite
操作字符串
StringReader与StringWriter
**************************************************
因为这两个流对象都操作的数组,并没有使用系统资源(底层资源)
所以,不用进行close关闭。而且关不关闭,这个流对象都能继续使用
1.源设备,
键盘 System.in , 硬盘 FileStream , 内存ArrayStream  !!!!!!!!!!
2.目的设备:
控制台 System.out   硬盘FileStream, 内存ArrayStream. !!!!!!!!!!


这里的源和目的都是内存
用流的读写思想来操作数据

import java.io.*;
class IoTextDemo
{
	public static void main (String[]  args)
	{
		//数据源
		ByteArrayInputStream  bis = new ByteArrayInputSream(“ABCDEFG”.getBytes());//都在内存中

		//数据目的
		ByteArrayOutputStream bos = new ByteArrayOutputStream();//都在内存中//不用写目的,因为目的被封装在内部,可变的字符数组


		int by = 0;
		while((by = bis.read()) != -1)
		{
			bos.write(by);
		}

		System.out.println(bos.size());	//7
		System.out.println(bos.toString()); //ABCDEFG


	}


}

四十一.IO流转换流的字符编码

字符编码
字符流的出现是为了方便操作字符
更重要的是加入了编码转换

原理:!!!!!!
通过子类转换流来完成
InputStreamReader
OutputStreamWriter
在两个对象进行构造的时候加入字符集(也就是编码表)

常见的编码表
ASCII:美国标准信息交换码
用一个字节的7位可以表示

ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示(比如打头为1,怎么写都跟前面的都不一样)

GBK2312:中国的中文编码表。(两个字节高位都是1,兼容ASCII码)

GBK:中国的中文编码表升级,融合了更多的中文文字符号

Unicode:国际标准码,融合了多种文字
所有文字都用两个字节来表示,java语言使用的就是unicode

UTF-8:最多用三个字节来表示一个字符

import java.io.*;
class IoTextDemo
{
	public static void main(String[] args) throw IOException
	{
		readText();
	}

}

public static void readText() throws IOException
{
	InputStreamReader isr = InputStreamReader(new FileInputStream(“gbk.txt”),”GBK”);

	char[] buf = new char[10];
	int len = isr.read(buf);

	String str = new String (buf, 0, len);

	System.out.printlb(str);
	isr.close();



}

public static void writeText() throws IOException
{
	OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(“utf.txt”),”UTF-8”);

	osw,write(“你好”);

	osw.close();

}

四十二.编码解码

编码:字符串变成字节数组
解码:字节数组变成字符串

String -- >byte[] ;str.getBytes(charsetName);
byte  -- > String: new String(byte[],charsetName);

import  java.util.*;
class EncideDemo
{
	public static void main(String[] args) throws Exception
	{
		String s = “你好”;
		byte[]  b1 = s.getBytes(“utf-8”); //编码

		System.out.println(Arrays.toString(b1));  //打印出他的字节
		String s1 = new String(b1 , “UTF-8”);

		System.out.println(“s1=”+s1);  //解码

	}

	//解码错了,在编回去,就OK了
	public static void  method_1()
	{
		String s = "你好";
		byte[] b1 = s.getBytes("GBK");

		System.out.println(Arrays.toString(b1));  //打印出按照GBK编码的每个字节

		String s1 = new String (b1,"iso8859-1");
		System.out.println("s1="+s1);//打印解码出的字符

		byte[] b2 = s1.getBytes("iso8859-1");
		System.out.println(Arrays.toString(b2)); //按照iso8859编码出的每个字节

		String s2 = new String(b2,"gbk");
		System.out.println("s2= "+s2);
	}
	!!!!!
	//解码错了,在编回去,不行了
	//往回编的时候编错了,因为GBK,UTF-8都识别中文,服务器用的是IOS8859
	//GBK用两个字节编码中文,UTF-8用三个,这是根本原因,用三个的原因,是因为识别到了使用三个字节的格式
	//UTF编码原理
	//utf编码是不定长编码,每一个字符的长度从1-6个字
	//节不等。另外,utf编码自带简单的校验功能。一般来讲,英文字母都是用一个字节表示,而汉字使用三个字节
	public static void  method_2()
	{
		String s = "你好";
		byte[] b1 = s.getBytes("GBK");

		System.out.println(Arrays.toString(b1));  //打印出按照GBK编码的每个字节

		String s1 = new String (b1,"UTF-8");
		System.out.println("s1="+s1);//打印解码出的字符

		byte[] b2 = s1.getBytes("UTF-8");
		System.out.println(Arrays.toString(b2)); //按照iso8859编码出的每个字节

		String s2 = new String(b2,"gbk");
		System.out.println("s2= "+s2);
	}



}

四十三.联通问题

UTF-8是读取三个字节成一个中文,
怎么判断取一个字节,还是去两个字节,还是三个字节
联通这两个字的编码正好符合UTF-8取两个字节的规则,所以乱码,他是三个字节做一个中文


开头 0  读一个字节
字节 1 0 位 6-0


开头110
第二字节10   读两个字节


字节 1 1 1 0 位 10-6


字节 2 1 0 位 5-0




第三个字节
字节 1 1 1 1 0 位 15-12


字节 2 1 0 位 11-6


字节 3 1 0 位 5-0

class EncodeDemo2
{
	public static void main(String[] args)throws Exception
	{
		String s = "联通";
		byte[] by = s.getBytes("gbk");
		for(byte b:by)
		{
			System.out.println(Integer.toBinaryString(b&255))//打印成二进制//取最后八位
		}


	}


}

四十四.练习

需求:
有五个学生,每个学生有三门课的成绩
从键盘输入以上数据(包括姓名,三门课成绩),
输入的格式:如:zhangsan , 30 , 40 ,60计算出总成绩,
并把学生的信息和计算出的总分数高低顺序存档在磁盘文件”stud.txt”中


1.描述学生对象
2.定义一个可操作学生对象的工具类。


思想:
1.通过获取键盘录入一行数据,并将该行中的信息取出封装成对象。
2.因为学生有很多,那么就需要存储,使用到集合,因为对学生的总分排序
所以可以使用TreeSet.
3.将集合的信息写入到一个文件中。

import java.io.*;
import java.util.*;

class IoTextDemo
{
	public static void main(String[] args) throws IOException
	{
		TreeSet<Student> stus = StudentInfoTool.getStudents();//默认顺序从小到大,现在从大到小
		StudentInfoTool.writeToFile(stus);

	
	}
}
class StudentInfoTool
{
	public static TreeSet<Student> getStudents()throws IOException
	{
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		TreeSet<Student> ts = new TreeSet<Student>();

		String line = null;

		while((line = bufr.readLine()) != null)
		{
			if("over".equals(line))
			{
				break;
			}
			//把输入的字符按逗号区分开
			String[] info = line.split(",");
			//自己写的时候就卡在这个地方(怎么把输入的数据添加到集合中)
			//parseInt(String s)将字符串参数作为有符号的十进制数进行解析
			Student stu = new Student(info[0],Integer.parseInt(info[1]),Integer.parseInt(info[2]),Integer.parseInt(info[3]));
	
			ts.add(stu);
		}
			bufr.close();

			return ts;
	}
	public static void writeToFile(TreeSet<Student> ts1) throws IOException
	{
		BufferedWriter bufw = new BufferedWriter(new  FileWriter("E:\\hebing\\Stu_info.txt") );

		for(Student s:ts1)
		{
			bufw.write(s.toString()+'\t');
			bufw.write(s.getSum()+"");
			bufw.newLine();
			bufw.flush();
		
		}

		bufw.close();

	
	
	}
}

//因为要排序,所以选择TreeSet,这里就用排序两种方法之一实现Comparable
class Student implements Comparable<Student>
{
	private String name;
	private int cn;
	private int en;
	private int math;
	private int sum;
	
	

	Student(String name , int cn , int en , int math)
	{
		this.name = name;
		this.cn = cn;
		this.en = en;
		this.math = math;
		this.sum = cn+en+math;
	
	}
	public String getName()
	{
		return name;
	}
	public int getSum()
	{
		return sum;
	}
	public int hashCode()
	{
	
		return name.hashCode()+sum*2;
	
	}
	public boolean equals(Student obj)
	{
		
		return (this.name.equals(obj.name))&&(this.sum == obj.sum);
	
	}
	//继承comparable需要复写compareTo这个方法
	public  int compareTo(Student s)
	{
		//这个地方写错了!!!!!
		int num = new Integer(this.sum).compareTo(new Integer(s.sum));

		if(num == 0)
		{
		
			return this.name.compareTo(s.name);
		}
		return num;
	
	}
	public String toString()
	{
		//等会把数据按照这样的格式写入文件中
		return name+","+en+","+cn+","+math+","+sum;
	}
}






你可能感兴趣的:(Java基础(20,21)IO流)