黑马程序员——IO复习小结(二)

读取键盘录入

System.out:对应的是标准输出设备,控制台
System.in:对应的是标准输入设备,键盘

需求:
通过键盘录入数据。
当录入一行数据后,就将该行数据进行打印。
如果录入的数据是over,那么停止录入。

通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。
也就是readLine方法。

那么能不能直接使用readLine方法来完成键盘录入一行数据的读取呢?

readLine方法是字符流BufferedReader类中的方法。
而键盘录入的read方法时字节流InputStream的方法。

那么能不能将字节流转成字符流,再使用字符流缓冲区的readLine方法呢?

import java.io.*;

class  ReadIn
{
	public static void main(String[] args) throws IOException
	{
		InputStream in = System.in;

		StringBuilder sb = new StringBuilder();
		
		//一次读取一行再打印
		while (true)
		{
			int ch = in.read();
			if (ch=='\r')
				continue;
			if (ch=='\n')
			{
				String s = sb.toString();
				if("over".equals(s))
					break;
				System.out.println(s.toUpperCase());
				sb.delete(0,sb.length());
			}
			else
				sb.append((char)ch);
		}
		
		in.close();
	}
}


通过字节流与字符流的转换来完成键盘的录入,比较方便。

因为BufferedReader 与BufferedWriter中存在整行操作的方法。

readLine();writeLine();

import java.io.*;

class  TransStreamDemo
{
	public static void main(String[] args) throws IOException
	{
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

		BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));


		String line = null;

		while ((line = bufr.readLine())!=null)
		{
			if ("over".equals(line))
				break;
			System.out.println(line.toUpperCase());
			bufw.write(line.toUpperCase());
			bufw.newLine();
			bufw.flush();
		}
		bufr.close();
	}
}



流的基本操作规律及实现思路
1,
源:键盘录入
目的:控制台


2,需求:想把键盘录入的数据存储到一个文件中。
源:键盘录入
目的:文件


3,需求:想要将一个文件的数据打印在控制台上。
源:文件
目的:控制台


流操作的基本规律:
最痛苦的就是流对象有很多,不知道该用哪个。




通过三个明确来完成。
1,明确源和目的。
源:输入流。 InputStream Reader
目的:输出流。 OutputStream Writer
2,明确操作的数据是否是纯文本。
是:字符流。
不是:字节流。
3,当体系明确后,再明确要使用哪个具体的对象。
通过设备来进行区分。
源设备:内存,硬盘,键盘。
目的设备:内存,硬盘,控制台。


1,将一个文本文件中的数据存储到另一个文件中,复制文件。
源:因为是源,所以使用读取流。 InputStream Reader
是不是操作文本文件:是!这时就可以选择Reader
这样体系就明确了。
接下来明确要使用该体系中的哪个对象。
明确设备:硬盘上的一个文件。
Reader体系中可以操作文件的对象FileReader

是否需要提高效率:是! 加入Reader体系中的缓冲区:BufferedReader

FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);

目的:OutputStream Writer
是不是纯文本:是!所以用Writer
设备:硬盘上的一个文件。
Writer体系中可以操作文件的对象FileWriter

是否需要提高效率:是! 加入Reader体系中的缓冲区:BufferedWriter

FileWriter fw = new FileReader("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);

练习:将一个图片文件中的数据存储到另一个文件中,复制文件。要按照以上格式自己完成三个明确。
源:InputStream Reader
是不是操作文本文件:不是! InputStream
设备:硬盘上的一张图片 FileInputStream


目的:OutputStream Writer
是不是操作文本文件:不是! OutputStream
设备:硬盘上的一张图片 FileOutputStream
--------------------------------------------------------------------

2,需求:将键盘录入的数据保存到一个文件中。
这个需求中,有源和目的都存在,那么分别分析:
源:InputStream Reader
是不是纯文本?是! Reader
设备:键盘,对应的对象System.in
不是选择Reader吗?System.in对应的不是字节流吗?
为了操作键盘的文本数据方便,转成字符流按照字符串操作最方便。
所以既然明确了Reader,那么就将System.in转换成字符流。
用了Reader体系中转换流,InputStreamReader
需要提高效率吗?需要!BufferedReader

InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader bufr = new BufferedReader(isr);


目的:OutputStream Writer
是不是纯文本?是! Writer
设备:硬盘上的一个文件。使用FileWriter
需要提高效率吗?需要!BufferedWriter

FileWriter fw = new FileWriter("c.txt");
BufferedWriter bufw = new BufferedWriter(fw);


*************************************************************************
扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存储到文件中。

目的:OutputStream Writer
是不是纯文本?是! Writer
设备:硬盘上的一个文件。使用FileWriter
FileWriter使用的是默认编码表:GBK


但是存储时需要加入指定编码表,而指定的编码表只有转换流可以指定。
所以要使用的对象是OutputStreamWriter
而该转换流对象要接收一个字节输出流,而且还可以操作的文件的字节输出流。FileOutputStream
需要提高效率吗?需要!BufferedWriter


OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt","UTF-8"));
BufferedWriter bufw = new BufferedWriter(osw);


所以,记住。转换流什么时候使用?
字符和字节的桥梁,通常涉及到字符编码转换时需要用到转换流。


*************************************************************************
练习:将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。
源:InputStream Reader
是不是纯文本?是! Reader
设备:硬盘上的一个文件。使用FileReader
是否需要提高效率?是,BufferedReader


目的:OutputStream Writer
是不是纯文本?是! Writer
设备:控制台,所以使用OutputStreamWriter
是否需要提高效率不?是,BufferedWriter

下面代码对应上面的练习及思路:
import java.io.*;

class  TransStreamDemo
{
	public static void main(String[] args) throws IOException
	{
		System.setIn(new FileInputStream("文件说明.txt"));
		System.setOut(new PrintStream("改变标准输入输出设备.txt"));
		
		//键盘最常见写法
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

		BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));



		String line = null;

		while ((line = bufr.readLine())!=null)
		{
			if ("over".equals(line))
				break;
			//System.out.println(line.toUpperCase());
			bufw.write(line.toString());
			bufw.newLine();
			bufw.flush();
		}
		bufr.close();
		
		//test_1();
		//test_2();
	}

	public static void test_2() throws IOException
	{
		/*
		练习:将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。
		源:InputStream		Reader
		是不是纯文本?是!	Reader
		设备:硬盘上的一个文件。使用FileReader
		是否需要提高效率?是,BufferedReader

		目的:OutputStream	Writer
		是不是纯文本?是!	Writer
		设备:控制台,所以使用OutputStreamWriter
		是否需要提高效率不?是,BufferedWriter
		*/
		BufferedReader bufr = new BufferedReader(new FileReader("文件说明.txt"));
		BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

		String buf = null;
		while ((buf = bufr.readLine())!=null)
		{
			bufw.write(buf);
			bufw.newLine();
			bufw.flush();
		}
		bufr.close();
		bufw.close();
	}

	public static void test_1() throws IOException
	{
		/*
		练习:将一个图片文件中的数据存储到另一个文件中,复制文件。要按照以上格式自己完成三个明确。
		源:InputStream		Reader
		是不是操作文本文件:不是!	InputStream
		设备:硬盘上的一张图片		FileInputStream

		目的:OutputStream	Writer
		是不是操作文本文件:不是!	OutputStream
		设备:硬盘上的一张图片		FileOutputStream
		*/
		
		FileInputStream fis = new FileInputStream("picture.png");

		FileOutputStream fos = new FileOutputStream("picture_new.png");

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

	}
}


File类
File类的常见方法:
1,创建
boolean createNewFile();
在指定位置创建文件,如果该文件已经存在,则不创建文件返回false。
和输出流不一样,输出流对象在建立的时候就会创建文件,而且文件存在时会覆盖。
boolean mkdir();
创建文件夹。
boolean mkdirs();
创建多级文件夹。

2,删除
boolean delete();
删除失败返回false。
void deleteOnExit();
在程序退出时删除指定文件。

3,判断
boolean exists();
文件是否存在。
boolean isFile();
判断是否为文件。
boolean ifDirectory();
判断是否为文件夹。
boolean isHidden();
判断是否为隐藏文件或文件夹。
boolean isAbsolute();
判断是否为绝对路径,如果是绝对路径,即使文件或文件夹不存在,也返回ture。

4,获取信息
getName();
获取名称。
getPath();
获取抽象路径名,相对路径,封装什么返回什么。
getParent();
获取父目录,如果没有返回null。
该方法返回的是绝对路径中的文件父目录,如果是相对路径,就会返回null。
如果相对路径中有上一层目录,那么该目录就是返回结果。"abc\\a.txt"-->getParent();-->abc
String getAbsolutePath();
获取文件或文件夹的绝对路径。
long lastModified();
获取最后修改时间。
long length();
获取指定路径上文件的长度。
boolean renameTo(File f);
重新命名此抽象路径的文件。
String[] list();
String[] list(FilenameFilter filter);
返回指定目录下的所有文件名。
调用list方法的file对象必须是封装了一个目录,该目录还必须存在。
根据过滤器filter返回文件或文件夹名。
File[] listFiles();
File[] listFiles(FileFilter filter);
File[] listFiles(FilenameFilter filter);
返回指定目录下所有文件或文件夹封装成的对象。
根据过滤器filter返回不同的文件或文件夹。
File[] listRoots();
返回所有盘符。
File类的基本使用代码如下:
import java.io.*;

class MyFilenameFilter implements FilenameFilter
{
	public boolean accept(File dir, String name)
	{
		return name.endsWith(".java");
	}
}

class FileDemo2 
{
	public static void main(String[] args) 
	{
		//listDemo(new MyFilenameFilter());
		listFilesDemo();
	}

	public static void listFilesDemo()
	{
		File dir = new File("F:\\javazx\\19");

		File[] files = dir.listFiles();

		for (File f : files)
		{
			System.out.println(f.getName()+"\t"+f.length());
		}
	}

	public static void listDemo(FilenameFilter filter)
	{
		File dir = new File("F:\\javazx\\19");

		String[] names = dir.list(filter);
		
		System.out.println(names.length);
		for(String name : names)
		{
			System.out.println(name);
		}
	}
	
	public static void listDemo()
	{
		File f = new File("F:\\javazx\\19");

		String[] names = f.list();//调用list方法的file对象必须是封装了一个目录,该目录还必须存在

		for(String name : names)
		{
			System.out.println(name);
		}

	}

	public static void listRootsDemo()
	{
		File[] files = File.listRoots();

		for (File f : files)
		{
			System.out.println(f);
		}
	}
}

练习:列出指定目录下文件或者文件夹,包含子目录中的内容。
也就是列出指定目录下所有内容。
思路:因为目录中还有目录,只要使用同一个列出目录功能的函数完成即可。
在列出过程中出现的还是目录的话,还可以再次调用本功能。
也就是函数自身调用自身。
这种表现形式,或者变成手法,称为递归。
递归要注意:
1,限定条件。
2,要注意递归的次数,尽量避免内存溢出
import java.io.*;

class FileDemo3 
{
	public static void main(String[] args) 
	{
		File dir = new File("F:\\TestDirectory");
		showAllFiles(dir,0);
		//toBin(6);
		//System.out.println(getSum(10));
	}

	public static String getLevel(int level)
	{
		StringBuilder sb = new StringBuilder();
		for (int x = 0; x<level; x++)
		{
			sb.append("  ");
		}
		sb.append("|--");
		return sb.toString();
	}

	public static void showAllFiles(File dir,int level)
	{
		System.out.println(getLevel(level)+dir.getName());
		level++;
		File[] files = dir.listFiles();

		for(File f : files)
		{
			if(f.isDirectory())
				showAllFiles(f,level);
			else
				System.out.println(getLevel(level)+f.getName()+"  "+f.length());
		}
	}

	public static int getSum(int n)
	{
		if (n==1)
		{
			return 1;
		}
		else
			return n+getSum(n-1);
	}
	
	//递归简单例子
	public static void toBin(int num)
	{
		if (num>0)
		{
			toBin(num/2);
			System.out.print(num%2);
		}
	}
	

}



Properties集合

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

特有方法

1、设置

        Object setProperty(String key,String value);

        //设置键和值,调用Hashtable的方法put

2、获取

        String getProperty(String key);

        //指定key搜索value

        Set<String> stringPropertyName();

        //返回属性列表的键集,存入Set集合

3、加载流和存入流

        void load(InputStream ism);

        //从输入字节流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。

        void load(Readerreader);

        //从输入字符流中读取属性列表(键和元素对)。又称将流中的数据加载进集合。

        voidlist(PrintStream out);//将属性列表输出到指定的输出流

        void store(OutputStreamout,String comments);

        //对应load(InputStream )将属性列表(键值对)写入输出流。comments属性列表的描述。

        void store(Writerwriter, String comments);

        //对应load(Reader)将属性列表(键值对)写入输出流。comments属性列表的描述。

练习:用于记录应用程序运行次数。如果使用次数已到,那么给出注册提示。
/*
用于记录应用程序运行次数。
如果使用次数已到,那么给出注册提示。

很容易想到的是:计数器。
可是该计数器定义在程序中,随着程序的运行而在内存中存在,并进行自增。
可是随着该应用程序的退出,该技术器也在内存中消失了。
下一次再启动改程序,又重新开始从0计数.
这样不是我们想要的。

程序即使结束,该技术器的值也存在。
下次程序启动会先加载该计数器的值并加1后再重新存储起来。

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

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

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

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

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

class  RunCount
{
	public static void main(String[] args) throws IOException
	{
		Properties prop = new Properties();

		File file = new File("count.ini");
		if(!file.exists())
			file.createNewFile();
		
		FileInputStream fis = new FileInputStream(file);

		prop.load(fis);
		

		int count = 0;
		String value = prop.getProperty("time");
		
		if(value!=null)
		{
			count = Integer.parseInt(value);
			if(count>=5)
			{
				System.out.println("您好,使用次数已到,拿钱!");
				return ;
			}

		}

		count++;

		prop.setProperty("time",count+"");

		FileOutputStream fos = new FileOutputStream(file);

		prop.store(fos,"");

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


打印流
打印流:
该流提供了打印方法,可以将各种数据类型的数据都原样打印。

字节打印流:
PrintStream
构造函数可以接收的参数类型:
1,file对象:File
2,字符串路径:String
3,字节输出流:OutputStream

字符打印流:
PrinteWriter
构造函数可以接收的参数类型:
1,file对象:File
2,字符串路径:String
3,字节输出流:OutputStream
4,字符输出流:Writer

import java.io.*;

class  PrintStreamDemo
{
	public static void main(String[] args) throws IOException
	{
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

		FileWriter file = new FileWriter("test.txt");
		PrintWriter out = new PrintWriter(new BufferedWriter(file),true);

		String line = null;

		while ((line = bufr.readLine())!=null)
		{
			if ("over".equals(line))
				break;
			out.println(line);
			//out.flush();
		}

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


SequenceInputStream流的合并

equenceInputStream将多个读取流合并。也就是多个源变为一个源,方便操作。
文件的切割合并练习:
import java.io.*;
import java.util.*;

class  SplitFile
{
	public static void main(String[] args) throws IOException
	{
		File filein = new File("Ylvis - The Fox.mp3");
		splitFile(filein);
		
		File fileout = new File("Ylvis - The Fox\\Ylvis - The Fox.mp3");
		merge(fileout,"1.part","2.part","3.part","4.part");
	}

	//合并文件
	public static void merge(File file,String... s) throws IOException
	{
		ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
		for (int x = 0; x<s.length; x++)
		{
			al.add(new FileInputStream(s[x]));
		}

		final Iterator<FileInputStream> it = al.iterator();

		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(file);

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

		fos.close();
		sis.close();
		
	}

	//切割文件
	public static void splitFile(File file) throws IOException
	{
		FileInputStream fis = new FileInputStream(file);

		FileOutputStream fos = null;
		byte[] buf = new byte[1024*1024];
		int len = 0;
		int count = 1;
		while ((len = fis.read(buf))!=-1)
		{
			fos = new FileOutputStream((count++)+".part");
			fos.write(buf,0,len);
			fos.close();
		}

		fis.close();
	}
}


ObjectStream对象的序列化
对象序列化对应的两个类:
ObjectInputStream
ObjectOutputStream

要注意的是被序列化的对象一定要实现接口Serializable。Serializable为标记接口,没有需要实现的方法。

1、写入流对象:

        1)创建对象写入流,与文件关联,即传入目的

        2)通过写入writeObject(Object obj)方法,将对象作为参数传入,即可写入文件

2、读取流对象

        1)创建对象读取流,与文件关联,即传入源

        2)通过readObject()方法,读取文件中的对象,并返回这个对象

注:

        1、静态成员不能被序列化

        2、非静态成员要不被序列化,可以用关键字transient修饰,保证非静态成员保存在堆内存中,不能存入文件中。

import java.io.*;
class ObjectStreamDemo 
{
	public static void main(String[] args) throws Exception
	{
		writeObj();
		readObj();
	}
	public static void readObj() throws Exception
	{
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));

		Person p = null;
		try
		{
			while ((p = (Person)ois.readObject())!=null)
			{System.out.println(p);}
		}
		catch (Exception e)
		{
			System.out.println("到达文件末尾");
		}
		ois.close();
	}
	public static void writeObj() throws IOException
	{
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));

		oos.writeObject(new Person("zhangsan",35));
		oos.writeObject(new Person("zhangsan1",35));
		oos.close();
	}
}


PipedStream管道流

管道流:

PipedInputStreamPipedOutputStream

特点:

         a、输入输出可以直接进行连接,不用再借助数组或集合等容器进行临时存储。     

        b、一般结合多线程使用。通常,数据由某个线程写入PipedOutputStream对象,并由其他线程从连接的 PipedInputStream 读取。

 

常见操作步骤

        1、要先创建一个读和写的两个类,实现Runnable接口,因为是两个不同的线程,覆盖run方法,注意,需要在内部处理异常。

        2、创建两个管道流,并用connect()方法将两个流连接

        3、创建读写对象,并传入两个线程内,并start执行。

import java.io.*;
class Read implements Runnable
{
	private PipedInputStream in;
	Read(PipedInputStream in)
	{
		this.in = in;
	}
	public void run()
	{
		try
		{
			byte[] buf = new byte[1024];
			int len = in.read(buf);

			String s = new String(buf,0,len);
			System.out.println(s);
			in.close();
		}
		catch (IOException e)
		{
			throw new RuntimeException("管道流读取失败");
		}
	}
}

class Write implements Runnable
{
	private PipedOutputStream out;
	Write(PipedOutputStream out)
	{
		this.out = out;
	}
	public void run()
	{
		try
		{
			out.write("piped lai la".getBytes());
			out.close();
		}
		catch (IOException e)
		{
			throw new RuntimeException("管道流读取失败");
		}
	}
}

class  PipedStreamDemo
{
	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();
	}
}

RandomAccessFile类

一、概述

        1RandomAccessFile此类的实例支持对随机访问文件的读取和写入,自身具备读写方法。

        2、该类不算是IO体系中的子类,而是直接继承Object,但是它是IO包成员,因为它具备读写功能,内部封装了一个数组,且通过getFilePointer方法获取指针位置,来对数组的元素进行操作,同时可通过seek方法改变指针的位置。

        3、可以完成读写的原理:内部封装了字节输入流和输出流。

        4、构造函数:RandomAccessFile(File file,String mode),可已从它的构造函数中看出,该类只能操作文件(可以传入文件名字符串),而且操作文件还有模式:只读“r”、读写“rw”等四种模式。

注:如果模式为只读r,则不会创建文件,会去读一个已存在的文件,若文件不存在,则会出现异常。如果模式为读写rw,且该对象的构造函数要操作的文件不存在,会自动创建;如果存在,则不会覆盖。

 

特有方法

        1seek(long pos)//调整对象中指针。来进行指定位置的数据读取和写入。数据要有规律。如果设置的指针位置已有数据,写入时将会将其修改。用seek可以表示随机读写访问。

        2int skipBytes(int n):跳过指定字节数,不可往前跳

 RandomAccessFile中也有对基本数据类型进行读写的方法。还有readLine方法。

 

使用步骤

        1、创建RandomAccessFile对象

        2、将数据写入到指定文件中

        3、读取指定文件中的数据

注意:要单独读取后面的数据,可以使用seek方法调整指针,或skipBytes方法跳过指定字节数,这种通过改变指针位置的方式,取出相应的数据。

import java.io.*;
class RandomAccessFileDemo 
{
	public static void main(String[] args) throws IOException
	{
		//writeFile_2();
		//readFile();
		//System.out.println(Integer.toBinaryString(258));
	}
	public static void readFile()throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("ran.txt","r");
		//调整对象中指针。
		//raf.seek(8*1);
		//跳过指定的字节数
		raf.skipBytes(8);
		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();
	}

	public static void writeFile_2()throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
		raf.seek(8*0);
		raf.write("周期".getBytes());
		raf.writeInt(103);
		raf.close();
	}

	public static void writeFile()throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
		raf.write("李四".getBytes());
		raf.writeInt(97);
		raf.write("王五".getBytes());
		raf.writeInt(99);
		raf.close();
	}
}

基本数据类型的数据的流对象

DataInputStream与DataOutputStream
可以用于操作基本数据类型的数据的流对象。

方法:

  

        byte            byte readbyte()

        int               intreadInt()

        boolean       boolean readBoolean()

        double        doublereadDouble()

String readUTF();//对应writeUTF,读取以UTF-8修改版编码写入的字符串

        byte           writeByte(int b);//b的低八位写入

        int              writeInt(int n)  

        boolean      writeBoolean(boolean b)    

        double        writeDouble(double d)  

writeUTF(String str);//以与机器无关方式使用UTF-8修改版编码将一个字符串写入基础输出流。

import java.io.*;
class DataStreamDemo 
{
	public static void main(String[] args) throws IOException
	{
		writeData();
		readData();
		writeUTFDemo();
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");
		osw.write("你好");
		osw.close();
		readUTFDemo();

	}
	public static void readUTFDemo()throws IOException
	{
		DataInputStream dis = new DataInputStream(new FileInputStream("utf.txt"));

		String s = dis.readUTF();

		System.out.println(s);
		dis.close();
	}



	public static void writeUTFDemo()throws IOException
	{
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("utfdate.txt"));

		dos.writeUTF("你好");

		dos.close();
	}

	public static void readData()throws IOException
	{
		DataInputStream dis = new DataInputStream(new FileInputStream("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();
	}
	public static void writeData()throws IOException
	{
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));

		dos.writeInt(234);
		dos.writeBoolean(true);
		dos.writeDouble(9887.543);

		dos.close();

		ObjectOutputStream oos = null;
		oos.writeObject(new O());

		
	}
}


字符编码表

概述

1、字符流的出现为了方便操作字符。

2、更重要的是加入了编码的转换,即转换流。

3、通过子类转换流来完成。在两个对象进行构造的时候,可以加入字符集(即编码表),可传入编码表的有:

        1)转换流:InuputStreamReaderOutputStreamWriter

        2)打印流:PrintStreamPrintWriter,只有输出流

4、编码表的由来

       计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。

5、常见的编码表:

        1ASCII:美国标准信息交换码表。用一个字节的7位表示

        2IOS8859-1:拉丁码表;欧洲码表。用一个字节的8位表示

        3GB2312:中国的中文编码表()早期

        4GBK:中国的中文编码表升级,融合了更多的中文文字字符。打头的是两个高位为1的两个字节编码。为负数

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

        6UTF-8:最多用三个字节表示一个字符的编码表,根据字符所占内存空间不同,分别用一个、两个、三个字节来编码。

UTF-8编码格式:

        一个字节:0开头

        两个字节:字节一  ---> 110    位数:10 ~ 6

                            字节二  ---> 10     位数:5 ~ 0

        三个字节:字节一  ---> 110    位数:15 ~ 12

                            字节二  ---> 10     位数:11 ~ 6

                         字节三 ---> 10     位数:5 ~ 0

 

转换流的编码应用

        1、可以将字符以指定编码格式存储。

        2、可以对文本数据指定编码格式来解读。

        3、指定编码表的动作由构造函数完成。

 

编码和解码

1、编码:字符串变成字节数组

        1)默认字符集: 

              String  --->  byte[]  srt.getBytes()

        2)指定字符集:

              String  --->  byte[]  srt.getBytes(charsetName)

2、解码:字节数组变成字符串

        1)默认字符集: 

              byte[]  --->  String new String(byte[])

        2)指定字符集: 

              byte[]   --->  String newString(byte[],charsetName)

 

对于编码和解码的字符集转换注意事项

        1、如果编码失败,解码就没意义了。

        2、如果编码成功,解码出来的是乱码,,则需对乱码通过再次编码(用解错码的编码表),然后再通过正确的编码表解码。针对于IOS8859-1是通用的。

        3、如果用的是GBK编码,UTF-8解码,此时通过再次编码后解码的方式,就不能成功了,因为UTF-8也支持中文,在UTF-8解的时候,会将对应的字节数改变,所以不会成功。

        如使用了错误的解码表:


        4、特别注意:对于中文的”联通“,这两个字比较特别,它的二进制位正好是和在UTF-8中两个字节打头的相同,所以在文本文件中,如果单独写“联通”或者和满足UTF-8编码格式的字符一起保存时,记事本就会用UTF-8来进行解码动作,这样显示的就会是乱码。


IO综合练习,存储信息
有五个学生,每个学生有三门课的成绩,
从键盘输入以上数据。
输入的格式:张三,30,40,60计算出总成绩,
并把学生的信息和计算出的总分数高低顺序存放在磁盘文件"stud.txt"中。
步骤及思路:
1,描述学生对象
2,定义一个可操作学生对象的工具类。
思想:
1,通过获取键盘录入的一行数据,并将该行数据中的信息取出,封装成学生对象
2,因为学生对象有很多,那么就需要存储,使用到集合,因为要对学生的总分排序,
所以可以使用TreeSet。
3,将集合中的信息写入到文件中。

import java.io.*;
import java.util.*;
class Student implements Comparable<Student>,Serializable
{
	private String name;
	int cScore,mScore,eScore;
	int sumScore;
	Student(String name,int cScore,int mScore,int eScore)
	{
		this.name = name;
		this.cScore = cScore;
		this.mScore = mScore;
		this.eScore = eScore;
		sumScore = cScore+mScore+eScore;
	}
	public String getName()
	{
		return name;
	}
	public int getSumScore()
	{
		return sumScore;
	}
	public int hashCode()
	{
		return name.hashCode()+sumScore*13;
	}
	public boolean equals(Object obj)
	{
		if (!(obj instanceof Student))
			throw new ClassCastException("类型不匹配");
		Student s = (Student)obj;
		return this.name.equals(s.name) && this.sumScore==s.sumScore;
	}
	public int compareTo(Student s)
	{
		int num = new Integer(this.sumScore).compareTo(new Integer(s.sumScore));
		if (num == 0)
			return this.name.compareTo(s.name);
		return num;
	}
	public String toString()
	{
		return "student["+name+","+cScore+","+mScore+","+eScore+","+sumScore+"]";
	}
}

class StudentInfoTool
{
	public static Set<Student> getStudents() throws IOException
	{
		return getStudents(null);
	}
	public static Set<Student> getStudents(Comparator<Student> cmp) throws IOException
	{
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		Set<Student> ts = null;
		if (cmp==null)
			ts = new TreeSet<Student>();
		else
			ts = new TreeSet<Student>(cmp);
		String line = null;
		while ((line = bufr.readLine())!=null)
		{
			if ("over".equals(line))
				break;
			String[] s = line.split(",");
			ts.add(new Student(s[0],Integer.parseInt(s[1]),Integer.parseInt(s[2]),Integer.parseInt(s[3])));
		}
		return ts;
	}
	public static void showStudents(Set<Student> stus)
	{
		Iterator<Student> it = stus.iterator();

		while (it.hasNext())
		{
			System.out.println(it.next().toString());
		}
	}
	public static void writeToFile(Set<Student> stus,File file) throws Exception
	{
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
		
		Iterator<Student> it = stus.iterator();

		while (it.hasNext())
		{
			oos.writeObject(it.next());
			oos.flush();
		}
		oos.close();
	}
	public static Set<Student> readToFile(File file) throws Exception
	{
		return readToFile(file,null);
	}
	public static Set<Student> readToFile(File file,Comparator<Student> cmp) throws Exception
	{
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
		
		Set<Student> stus = null;
		if (cmp==null)
			stus = new TreeSet<Student>();
		else
			stus = new TreeSet<Student>(cmp);
		Student s = null;
		try
		{
			while ((s = (Student)ois.readObject())!=null)
			{
				stus.add(s);
			} 
		}
		catch (Exception e)
		{
		}
		
		ois.close();
		return stus;
	}
}

class StudentInfoTest 
{
	public static void main(String[] args) throws Exception
	{
		
		Comparator<Student> cmp = Collections.reverseOrder();
		//Set<Student> stus = StudentInfoTool.getStudents(cmp);
		//StudentInfoTool.showStudents(stus);
		//StudentInfoTool.writeToFile(stus,new File("stuInfo.object"));
		Set<Student> stus1 = StudentInfoTool.readToFile(new File("stuInfo.object"),cmp);
		StudentInfoTool.showStudents(stus1);
	}
}














  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值