java 之 IO

一:IO流概述:

IO(Input     Output)

IO流用来处理设备之间的数据传输,java对数据的操作是通过流的方式,java用于操作流的对象都在IO包中

流按照操作数据分为:字节流与字符流

流按照流向分为:输入流,输出流

字符流内有编码表,图片的时候用字节流

二:流常用的基类:(输入流是读,输出流是写)

字节流的抽象基类:InputStream    OutputStream

字符流的抽象基类:Reader           Writer

注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀

如:InputStream的子类FileInputStream

如:Reader的子类FileReader

三:

3.1.1 FileWriter:

IO流是用于操作数据的,那么数据的最常见体现形式是:文件。
(1)例子:需求:在硬盘上,创建一个文件并写入一些文字数据。
找到一个专门用于操作文件的Writer子类对象。FileWriter。  后缀名是父类名。 前缀名是该流对象的功能。

import java.io.*;
class  FileWriterDemo
{
	public static void main(String[] args) throws IOException
	{
		//创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。
		//而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
		//其实该步就是在明确数据要存放的目的地。
		FileWriter fw = new FileWriter("demo.txt");

		//调用write方法,将字符串写入到流中。
		fw.write("abcde");

		//刷新流对象中的缓冲中的数据。
		//将数据刷到目的地中。
		fw.flush();


		//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
		//将数据刷到目的地中。
		//和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
		fw.close();
	}
}
(2)IO异常处理方式:(try----catch-----finally)

import java.io.*;
class FileWriterDemo2 
{
	public static void main(String[] args) 
	{
		FileWriter fw = null;
		try{
			 fw = new FileWriter("k:\\demo.txt");//不存在异常(FileNotFoundException,系统不存在异常)

			fw.write("abfjrklfj");

			
		}catch(IOException e)
		{
			System.out.println("catch:"+e.toString());
		}
		finally
		{
			try
			{
				if(fw!=null)
					fw.close();
			}catch(IOException e)
			{
				System.out.println(e.toString());
			}
		}
	}
}
(3)每一次如果继续写入的话就会覆盖原来的数据,那么怎么才能续写不覆盖呢(传递一个true参数)

import java.io.*;
class FileWriterDemo3 
{
	public static void main(String[] args) 
	{
		//传递一个true参数,代表不覆盖已有的文件,并在已有文件的末尾处进行数据续写。
		FileWriter fw=null;
		try
		{
			fw = new FileWriter("demo.txt",true);
			fw.write("asdff");
			fw.write("jfo\r\nldfkjp");//windows系统 中用\r\n 表示换行,linux用\n表示换行
		}
		catch (IOException e)
		{
			System.out.println(e.toString());
		}
		finally
		{
			try{
				if(fw!=null)
					fw.close();
			}catch(IOException e)
			{
				System.out.println("cathc:"+e.toString());
			}
		}
			
	}
}
3.1.2 文件的两种读取方式:FileReader

第一种方式:一次读一个字符,依次往下读

例子程序:

import java.io.*;
class FileReaderDemo 
{
	public static void main(String[] args)throws Exception 
	{
		//创建一个文件读取流对象,和指定名称的文件相关联
		//要保证该文件是已经存在的,如果不存在,会发生FileNotFoundException
		FileReader fr = new FileReader("demo.txt");

		//调用读取流对象的read方法
		//read(): 一次读一个字符,而且会自动往下读
		int ch = 0;
		while((ch=fr.read())!=-1)
		{
			System.out.println("ch="+(char)ch);
		}
		/*
		while(true)
		{
			int ch = fr.read();
			if(ch!=-1)
			{
				System.out.println("ch="+(char)ch);
			}

			fr.close();
		}
		*/
	}
}

第二种方式:定义一个字符数组,一次读一串字符,依次往下读

例子程序:

import java.io.*;

class FileReaderDemo2 
{
	public static void main(String[] args) throws IOException
	{
		FileReader fr = new FileReader("demo.txt");
		//定义一个字符数组。用于存储读到字符。
		//该read(char[])返回的是读到字符个数。
		char[] buf = new char[1024];

		int num = 0;
		while((num=fr.read(buf))!=-1)
		{
			System.out.println(new String(buf,0,num));
		}
		fr.close();
	}
}

3.1.3拷贝文本文件(FileWriter,FileReader)

例子程序:

import java.io.*;
class CopyText 
{
	public static void main(String[] args) throws IOException
	{
		copy_2();
		
	}
	//从c盘读一个字符,就往d盘写一个字符
	public static void copy_1()throws IOException
	{
		//创建目的地
		FileWriter fw = new FileWriter("RuntimeDemo_copy.txt");
		//与已有文件关联
		FileReader fr = new FileReader("RuntimeDemo.java");
		int ch = 0;
		while((ch = fr.read())!=-1)
		{
			fw.write(ch);
		}
		fw.close();
		fr.close();

	}
	public static void copy_2()
	{
		FileWriter fw =null;
		FileReader fr = null;
		try{
			 fw = new FileWriter("SystemDemo_copy.txt");
			 fr = new FileReader("SystemDemo.java");

			 char[] buf = new char[1024];
			 int len= 0;
			 while((len=fr.read(buf))!=-1){
				fw.write(buf,0,len);
			 }
		}
			 catch(IOException e)
			{
				 throw new RuntimeException("读写失败");

			}
			finally
			{
				if(fr!=null)
					try
					{
						fr.close();
					}
					catch (IOException e)
					{
					}
				if(fw!=null)
					try
					{
						fw.close();
					}
					catch (IOException e)
					{
					}
			}
		

	}
}

3.2字符流的缓冲区:BufferedWriter,BufferedReader

缓冲区的出现提高了对数据的读写效率,缓冲区要结合流才可以使用,在流的基础上对流的功能进行了增强

缓冲区的出现是为了提高流的操作效率而出现的。所以在创建缓冲区之前,必须要先有流对象。该缓冲区中提供了一个跨平台的换行符。newLine();

例如:

import java.io.*;

class  BufferedWriterDemo
{
	public static void main(String[] args) throws IOException
	{
		//创建一个字符写入流对象。
		FileWriter fw = new FileWriter("buf.txt");

		//为了提高字符写入流效率。加入了缓冲技术。
		//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
		BufferedWriter bufw = new BufferedWriter(fw);

		for(int x=1; x<5; x++)
		{
			bufw.write("abcd"+x);
			bufw.newLine();
			bufw.flush();
		}

		//记住,只要用到缓冲区,就要记得刷新。
		//bufw.flush();

		//其实关闭缓冲区,就是在关闭缓冲区中的流对象。
		bufw.close();


	}
}

3.2.2BufferedReader------>readLine()

字符读取流缓冲区:
该缓冲区提供了一个一次读一行的方法 readLine,方便于对文本数据的获取。
当返回null时,表示读到文件末尾。readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。

例如:

import java.io.*;
class BufferedReaderDemo 
{
	public static void main(String[] args)throws IOException
	{
		//创建一个读取流对象,和文件相关联。
		FileReader fr = new FileReader("buf.txt");
		//为了提高效率。加入缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数。
		BufferedReader buf = new BufferedReader(fr);

		//String s  = buf.readLine();
		//System.out.println("s="+s);
		String line = null;
		while((line=buf.readLine())!=null)
		{
			System.out.println(line);
		}


		buf.close();
	}
}

通过缓冲区复制java文件到txt中例子程序:

import java.io.*;

class  CopyTextByBuf
{
	public static void main(String[] args) 
	{
		BufferedReader bufr = null;
		BufferedWriter bufw = null;

		try
		{
			bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));
			bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));

			String line = null;

			while((line=bufr.readLine())!=null)
			{
				bufw.write(line);
				bufw.newLine();
				bufw.flush();

			}
		}
		catch (IOException e)
		{
			throw new RuntimeException("读写失败");
		}
		finally
		{
			try
			{
				if(bufr!=null)
					bufr.close();
			}
			catch (IOException e)
			{
				throw new RuntimeException("读取关闭失败");
			}
			try
			{
				if(bufw!=null)
					bufw.close();
			}
			catch (IOException e)
			{
				throw new RuntimeException("写入关闭失败");
			}
		}
	}
}

根据readLine方法原理,自己定义一个类包含一个功能和readline方法一致的方法来模拟一下BufferedReader

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;


public class MyBufferedReaderTest {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		FileReader fr = new FileReader("1.txt");
		MyBufferedReader mb = new MyBufferedReader(fr);
		String line = null;
		while((line = mb.myReadLine())!=null){
			System.out.println(line);
		}
		mb.myClose();

	}

}
class MyBufferedReader{
	private FileReader fr;

	MyBufferedReader(FileReader fr){
		this.fr = fr;
	}
	public String myReadLine() throws IOException{
		StringBuilder sb = new StringBuilder();
		int ch = 0;
		while((ch = fr.read())!=-1){
			if(ch=='\r')
				continue;
			if(ch=='\n')
				return sb.toString();
			else
				sb.append((char)ch);
		}
		if(sb.length()!=0)
			return sb.toString();
		return null;
	}
	public void myClose() throws IOException{
		fr.close();
	}
}

3.3装饰设计模式:
当想要对已有的对象进行功能增强时,
可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
那么自定义的该类称为装饰类。
装饰类通常会通过构造方法接收被装饰的对象。
并基于被装饰的对象的功能,提供更强的功能。

例如人和super人的关系:其中super人是装饰类:

例子:

class Person
{
	public void chifan()
	{
		System.out.println("chifan");
	}
}
class SuperPerson
{
	private Person p;
	SuperPerson(Person p)
	{
		this.p = p;
	}
	public void superChifan()
	{
		System.out.println("kaiweijiu");
		p.chifan();
		System.out.println("甜点");
	}
}
class PersonDemo 
{
	public static void main(String[] args) 
	{
		Person p = new Person();
		//p.chifan();
		SuperPerson sp = new SuperPerson(p);
		sp.superChifan();
	}
}
装饰和继承的关系:

MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyBufferTextReader
|--MyMediaReader
|--MyBufferMediaReader
|--MyDataReader
|--MyBufferDataReader


class MyBufferReader
{
MyBufferReader(MyTextReader text)
{}
MyBufferReader(MyMediaReader media)
{}
}
上面这个类扩展性很差。
找到其参数的共同类型。通过多态的形式。可以提高扩展性。

class MyBufferReader extends MyReader
{
private MyReader r;
MyBufferReader(MyReader r)
{}
}

MyReader//专门用于读取数据的类。
|--MyTextReader
|--MyMediaReader
|--MyDataReader
|--MyBufferReader

以前是通过继承将每一个子类都具备缓冲功能。
那么继承体系会复杂,并不利于扩展。
现在优化思想。单独描述一下缓冲内容。
将需要被缓冲的对象。传递进来。也就是,谁需要被缓冲,谁就作为参数传递给缓冲区。
这样继承体系就变得很简单。优化了体系结构。
装饰模式比继承要灵活。避免了继承体系臃肿。
而且降低了类于类之间的关系。

练习:自定义装饰类

import java.io.*;
class MyBufferedReader extends Reader
{
	private Reader r;
	MyBufferedReader(Reader r)
	{
		this.r = r;
	}
	//可以一次读一行数据的方法
	public String myReadLine()throws IOException
	{
		//定义一个临时容器原BufferedReader封装的是字符数组
		//为了演示方便,定义一个StringBuilder容器。因为最终还是要将数据变成字符串
		StringBuilder sb = new StringBuilder();
		int ch = 0;
		while((ch=r.read())!=-1)
		{
			if(ch=='\r')
				continue;
			if(ch=='\n')
				return sb.toString();
			else
				sb.append((char)ch);
		}

		if(sb.length()!=0)
			return sb.toString();
		return null;
	}
	/*
	覆盖Reader类中的抽象方法
	*/
	public int read(char[] cbuf,int off,int len)throws IOException
	{
		return r.read(cbuf,off, len);

	}
	public void close()throws IOException
	{
		r.close();
	}
	public void myClose()throws IOException
	{
		r.close();
	}
}
class BufferedReaderDemo2
{
	public static void main(String[] args) throws IOException
	{
		FileReader fr = new FileReader("buf.txt");
		MyBufferedReader myBuf = new MyBufferedReader(fr);
		String line = null;
		while((line = myBuf.myReadLine())!=null)
		{
			System.out.println(line);
		}
		myBuf.myClose();
		
	}
}

3.4LineNumberReader(跟踪行号的缓冲字符输入流,是BufferedReader的子类)

此类定义了方法 setLineNumber(int)getLineNumber(),它们可分别用于设置和获取当前行号。  

默认情况下,行编号从 0 开始。

举例:

import java.io.*;
class  LineNumberReaderDemo
{
	public static void main(String[] args) throws IOException
	{
		FileReader fr = new FileReader("PersonDemo.java");
		LineNumberReader lnr = new LineNumberReader(fr);
		String line = null;
		lnr.setLineNumber(100);
		while((line = lnr.readLine())!=null)
		{
			System.out.println(lnr.getLineNumber()+":"+line);
		}
		lnr.close();
	}
}

模拟一个带行号的缓冲区:

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;


public class MyLineNumberReaderDemo {
	public static void main(String[] args) throws IOException {
		FileReader fr = new FileReader("1.txt");
		MyLineNumberReader ml = new MyLineNumberReader(fr);
		String line = null;
		ml.setMyLineNumber(100);
		while((line=ml.MyReadLine())!=null){
			System.out.println(ml.getMyLineNumber()+":"+line);
		}

	}

}
class MyLineNumberReader{
	private Reader fr;
	private int num=0;
	MyLineNumberReader(Reader fr){
		this.fr = fr;
	}
	public void setMyLineNumber(int num){
		this.num = num;
		
	}
	public int getMyLineNumber(){
		
		return num;
	}
	public String MyReadLine() throws IOException{
		num++;
		StringBuilder sb =new StringBuilder();
		int ch = 0;
		while((ch = fr.read())!=-1)
		{
			if(ch=='\r')
				continue;
			if(ch=='\n')
				return sb.toString();
			else
				sb.append((char)ch);
		}
		if(sb.length()!=0)
		{
			return sb.toString();
		}
		return null;

	}
	public void myClose()throws IOException
	{
		fr.close();
	}
	
	
}
3.5字节流的操作

字符流:

FileReader      FileWriter

BufferedReader  BufferedWriter

字节流:

InputStream  OutputStream

 

需求,想要操作图片数据。这时就要用到字节流。

举例:FileStream

import java.io.*;
class  FileStream
{
	public static void main(String[] args) throws IOException
	{
		readFile_3();
	}

	public static void readFile_3()throws IOException
	{
		FileInputStream fis = new FileInputStream("fos.txt");
		
//		int num = fis.available();
		byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区。不用在循环了。

		fis.read(buf);

		System.out.println(new String(buf));

		fis.close();
	}


	public static void readFile_2()throws IOException
	{
		FileInputStream fis = new FileInputStream("fos.txt");

		byte[] buf = new byte[1024];
		int len = 0;
		while((len=fis.read(buf))!=-1)
		{
			System.out.println(new String(buf,0,len));
		}

		fis.close();
		
	}



	public static void readFile_1()throws IOException
	{
		FileInputStream fis = new FileInputStream("fos.txt");

		int ch = 0;

		while((ch=fis.read())!=-1)
		{
			System.out.println((char)ch);
		}

		fis.close();
	}

	public static void writeFile()throws IOException
	{
		FileOutputStream fos = new FileOutputStream("fos.txt");
		

		fos.write("abcde".getBytes());

		fos.close();

		
	}
}

例子复制一个图片:(字符流也可以复制,但是图片可能出错,因为编码可能出错。)

思路:

1用字节读取流对象和图片的关联

2.用字节写入流对象创建一个图片文件。用于存储获取到的图片数据

3.通过循环读写完成数据的存储

4.关闭资源:

例子程序:CopyPic

 import java.io.*;
class  CopyPic
{
	public static void main(String[] args) 
	{
		FileOutputStream fos = null;
		FileInputStream fis = null;
		try
		{
			fos = new FileOutputStream("c:\\2.bmp");
			fis = new FileInputStream("c:\\1.bmp");

			byte[] buf = new byte[1024];

			int len = 0;

			while((len=fis.read(buf))!=-1)
			{
				fos.write(buf,0,len);
			}
		}
		catch (IOException e)
		{
			throw new RuntimeException("复制文件失败");
		}
		finally
		{
			try
			{
				if(fis!=null)
					fis.close();
			}
			catch (IOException e)
			{
				throw new RuntimeException("读取关闭失败");
			}
			try
			{
				if(fos!=null)
					fos.close();
			}
			catch (IOException e)
			{
				throw new RuntimeException("写入关闭失败");
			}
		}
	}
}

3.6 字节流的缓冲区 BufferedInputStream   BufferedOutputStream

举例:用字节流的缓冲区方法来复制一段音乐  CopyMp3

 import java.io.*;
public class CopyMp3 {
    public static void main(String[] args) throws IOException {
        long start = System.currentTimeMillis();
        copy_1();
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    }
    //通过字节流的缓冲区完成复制
    public static void copy_1() throws IOException
    {
        BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
        BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
        
        int by = 0;
        while((by = bufis.read())!=-1)
        {
            bufos.write(by);
        }
        bufos.close();
        bufis.close();
        
    }
}

自己定义字节流的缓冲区:(多看!!)

抓一批数据存到数组中去(count 表示数组的长度),然后在从数组从一个一个往外取(通过指针pos

import java.io.*;
public class MyBufferedInputStreamTest {
    public static void main(String[] args) throws IOException {
    
        copy_1();
    }
    public static void copy_1() throws IOException
    {
        MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("c:\\0.mp3"));
        BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
        
        int by = 0;
        while((by = bufis.myRead())!=-1)
        {
            bufos.write(by);//read在提升,write在强转
        }
        bufos.close();
        bufis.myClose();
        
    }
}
class MyBufferedInputStream
{
    private InputStream in;
    private byte[]  buf = new byte[1024*4];
    private int pos = 0,count = 0;
    MyBufferedInputStream(InputStream in){
        this.in = in;
    }
    //一次读一个字节,从缓冲区(字节数组)获取
    public int myRead() throws IOException
    {
        //通过in对象读取硬盘上数据,并存到buf中
        if(count==0){
            count = in.read(buf);
            if(count<0)
                return -1;
            pos = 0;
            byte b = buf[pos];
            count--;
            pos++;
            return b&255;//提升为一个int类型 那不还是-1吗?是-1的原因是因为在8个1前面补的是1导致的 那么只要我在前面补0,即可以保留原字节数据不变又可以避免-1的出现,
        }
        else if(count>0){
            byte b = buf[pos];
            count--;
            pos++;
            return b&0xff;//255的十六进制表现形式
        }
        return -1;
        
    }
    public void myClose() throws IOException
    {
        in.close();
    }
    
}

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

 System.in:对应的标准输入设备:键盘

举例:

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

import java.io.IOException;
import java.io.InputStream;
public class ReadIn {
    public static void main(String[] args) throws IOException {
        InputStream in = System.in;
        //int by= 0;
        //System.out.println('\r'+0);
        //System.out.println('\n'+0);
        /*while((by=in.read())!=-1)
        {
            System.out.println(by);
        }
        in.close();*/
        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);
            }
        }
    }
}

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

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

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

那么能不能将字节流转成字符流在使用字符流缓冲去的readLine方法呢?(InputStreamReader)

举例:

import java.io.*;
public class TransStreamDemo {
    public static void main(String[] args) throws IOException {
        //获取键盘录入
        InputStream in = System.in;
        //将字节流对象转成字符流对象,使用转换流InputStreamReader
        InputStreamReader isr = new InputStreamReader(in);
        //为了提高效率,将字符串进行缓冲区技术搞笑操作,使用BufferedReader
        BufferedReader buf = new BufferedReader(isr);
        String line=null;
        while((line=buf.readLine())!=null)
        {
            if("over".equals(line))
                break;
            System.out.println(line.toUpperCase());
        }
        buf.close();
    }
}

InputStreamReader   OutputStreamWriter转换流

举例:

import java.io.*;
public class TransStreamDemo {
    public static void main(String[] args) throws IOException {
        //获取键盘录入
        InputStream in = System.in;
        //将字节流对象转成字符流对象,使用转换流InputStreamReader
        InputStreamReader isr = new InputStreamReader(in);
        //为了提高效率,将字符串进行缓冲区技术搞笑操作,使用BufferedReader
        BufferedReader buf = new BufferedReader(isr);
        OutputStream out = System.out;
        OutputStreamWriter osw = new OutputStreamWriter(out);
        BufferedWriter buf1 = new BufferedWriter(osw);
        
        String line=null;
        while((line=buf.readLine())!=null)
        {
            if("over".equals(line))
                break;
            buf1.write(line.toUpperCase());
            buf1.newLine();
            buf1.flush();
        }
        buf.close();
    }
}

3.7流的操作规律:

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

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

FileWriter fw = new FileWriter("b.txt");

BufferedWriter bufw = new BufferedWriter(fw);

---------------------------------------

 

2,需求:将键盘录入的数据保存到一个文件中。

这个需求中有源和目的都存在。

那么分别分析

源:InputStream Reader

是不是纯文本?是!Reader

设备:键盘。对应的对象是System.in.

不是选择Reader吗?System.in对应的不是字节流吗?

为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。

所以既然明确了Reader,那么就将System.in转换成Reader

用了Reader体系中转换流,InputStreamReader

 

InputStreamReader isr = new InputStreamReader(System.in);

 

需要提高效率吗?需要!BufferedReader

BufferedReader bufr = new BufferedReader(isr);

 

 

 

目的:OutputStream  Writer

是否是存文本?是!Writer

设备:硬盘。一个文件。使用 FileWriter

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

需要提高效率吗?需要。

BufferedWriter bufw = new BufferedWriter(fw);

**************

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

目的:OutputStream  Writer

是否是存文本?是!Writer

设备:硬盘。一个文件。使用 FileWriter

但是FileWriter是使用的默认编码表。GBK.

但是存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。

所以要使用的对象是OutputStreamWriter

而该转换流对象要接收一个字节输出流。而且还可以操作的文件的字节输出流。FileOutputStream

 

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

 

需要高效吗?需要。

BufferedWriter bufw = new BufferedWriter(osw);

 

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

需要用到转换流。

3.7.2:改变标准的输入输出设备(PrintStream

举例程序:

import java.io.*;
public class CopyDemo {
	public static void main(String[] args) throws IOException {
		System.setIn(new FileInputStream("1.txt"));
		System.setOut(new PrintStream("5.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		String len = null;
		while((len = br.readLine())!=null){
			bw.write(len);
			bw.newLine();
			bw.flush();
		}
		br.close();
		bw.close();

	}
}

3.7.3异常的日志信息:

例子:

import java.io.IOException;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;


public class Log {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			int arr[] = new int [2];
			System.out.println(arr[3]);
		} catch (Exception e) {
			try{
				Date d = new Date();
				SimpleDateFormat sd = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
				String s = sd.format(d);
				PrintStream ps = new PrintStream("exception.log");
				ps.println(s);
				System.setOut(ps);
				
			}catch(IOException ex){
				throw new RuntimeException("日志创建失败");	
			}
			e.printStackTrace(System.out);
		}

	}

}

3.7.4系统信息:Property

例子:

import java.io.*;
import java.util.*;
public class SystemInfo {
    public static void main(String[] args) throws IOException {
        Properties prop = System.getProperties();
        //System.out.println(prop);不会换行
        System.setOut(new PrintStream("c.txt"));
        prop.list(System.out);
    }
}

3.8File

3.8.1 File定义:

1)用来将文件或者文件夹封装成对象

2)方便对文件与文件夹的属性信息进行操作

3File对象可以作为参数传递给流的构造函数,

4)了解File类中的常用方法

File类常见方法:

1,创建。

boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false

和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。

 

boolean mkdir():创建文件夹。

boolean mkdirs():创建多级文件夹。

2,删除。

boolean delete():删除失败返回false。如果文件正在被使用,则删除不了返回falsel

void deleteOnExit();在程序退出时删除指定文件。

功能展示例子:

 

 

3,判断。

boolean exists() :文件是否存在.

isFile():

isDirectory();

isHidden();

isAbsolute();

 

4,获取信息。

getName():

getPath():

getParent():

 

getAbsolutePath() 

long lastModified() 

long length() 

程序:

import java.io.File;
import java.io.IOException;

class FileDemo 
{
	public static void main(String[] args) throws IOException
	{
		method_4();
	}

	public static void method_5()
	{
		File f1 = new File("c:\\Test.java");
		File f2 = new File("d:\\hahah.java");

		sop("rename:"+f2.renameTo(f1));

	}

	public static void method_4()
	{
		File f = new File("9.txt");

		sop("path:"+f.getPath());
		sop("abspath:"+f.getAbsolutePath());
		sop("parent:"+f.getParent());//该方法返回的是绝对路径中的父目录。如果获取的是相对路径,返回null。
									//如果相对路径中有上一层目录那么该目录就是返回结果。



	}
	
	public static void method_3()throws IOException
	{
		File f = new File("D:\\Program Files");

		f.mkdir();// 创建此抽象路径名指定的目录。

		//记住在判断文件对象是否是文件或者目的时,必须要先判断该文件对象封装的内容是否存在。
		//通过exists判断。
		sop("dir:"+f.isDirectory());
		sop("file:"+f.isFile());
		sop(f.isAbsolute());
	
}

	public static void method_2() throws IOException
	{
		File f = new File("file.txt");
		boolean fx = f.createNewFile();
		sop("exists:"+f.exists());

		sop("execute:"+f.canExecute());//测试应用程序是否可以执行此抽象路径名表示的文件。

		//创建文件夹
		File dir = new File("abc\\kkk\\a\\a\\dd\\ee\\qq\\aaa");

		sop("mkdir:"+dir.mkdirs());//创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。
	}
	

	public static void method_1()throws IOException
	{
		File f = new File("file.txt");
		sop("create:"+f.createNewFile());//创建一个文件对象
		sop("delete:"+f.delete());//删除一个文件对象



		
	}

//创建File对象
	public static void consMethod()
	{
		//将a.txt封装成file对象。可以将已有的和为出现的文件或者文件夹封装成对象。
		File f1 = new File("a.txt");

		//
		File f2 = new File("c:\\abc","b.txt");


		File d = new File("c:\\abc");
		File f3 = new File(d,"c.txt");

		sop("f1:"+f1);
		sop("f2:"+f2);
		sop("f3:"+f3);

		File f4 = new File("c:"+File.separator+"abc"+File.separator+"zzz"+File.separator+"a.txt");


	}

	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

4.文件列表:(拿到当前目录下的文件)

listRoot(得到c:   d:...)  

listFile(new Filenamefilter)  文件过滤器

listFiles得到当前目录下的所有文件

文件列表演示程序:

import java.io.File;
import java.io.FilenameFilter;


public class FileDemo2 {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		//fileRoot();
		//listDemo2();
		File f = new File("E:\\");
		File[] files = f.listFiles();
		for(File fi:files){
			System.out.println(fi.getName()+"..."+fi.length());
		}
		

	}
	public static void listDemo2(){
		File f = new File("c:\\");
		String [] arr = f.list(new FilenameFilter(){

			public boolean accept(File dir, String name) {//文件名过滤器
				//System.out.println("dir"+dir+"..."+name);
				/*if(name.endsWith(".bmp"));
					return true;
				else{
						return false;
						
					}*/
				return name.endsWith(".bmp");	
			}
			
		});
		System.out.println("arr:"+arr.length);
		for(String name : arr){
			System.out.println(name);
		}
	}
	public static void  listDemo(){
		File f = new File("c:\\");
		String[]names = f.list();
		for(String name : names){
			System.out.println(name);
		}
	}
	public static void fileRoot(){
		File[] listroots = File.listRoots();//列出可用的文件系统根,列出机器中有效的盘符:c:,d:...
		for(File listroot:listroots){
			System.out.println(listroot);
		}
	}

}

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

列出文件中的文件

import java.io.File;
public class FileDemo3 {
	public static void main(String[] args) {
		File f = new File("c:\\Matlab7");
		showDir(f);

	}
	public static void showDir(File dir){
		File[] files = dir.listFiles();
		for(int x = 0;x<files.length;x++){
			if(files[x].isDirectory()){
				showDir(files[x]);
			}else{
				System.out.println(files[x]);
			}
		}
	}

}

列出目录下的所有内容,带层次:

import java.io.*;
class  FileDemo3
{
	public static void main(String[] args) 
	{
		File f = new File("c:\\Application Data");
		showDir(f,0);
	}
	public static String getLevel(int level)
	{
		StringBuilder sb = new StringBuilder();
		sb.append("|--");
		for(int x = 0;x<level;x++){
			sb.insert(0,"|  ");
		}
		return sb.toString();
	}
	public static void showDir(File dir,int level)
	{
		System.out.println(getLevel(level)+dir.getName());
		level++;
		File[] files = dir.listFiles();
		for(int x=0;x<files.length;x++){
			if(files[x].isDirectory()){
				showDir(files[x],level);
			}else{
				System.out.println(getLevel(level)+files[x]);
			}
		}
	}
}
删除一个带内容的目录。
删除原理:
在window中,删除目录从里面往外删除的。
既然是从里往外删除。就需要用到递归。

import java.io.File;


public class RemoveDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		File f = new File("c:\\wjn");
		remove(f);
	}
	public static void remove(File f){
		File[] files = f.listFiles();
		for(int x = 0;x<files.length;x++){
			if(files[x].isDirectory()){
				remove(files[x]);
			}
			else{
				System.out.println(files[x].toString()+"..."+files[x].delete());
			}
		}
		System.out.println(f+"dir:"+f.delete());
		
	}

}

练习
将一个指定目录下的java文件的绝对路径,存储到一个文本文件中。
建立一个java文件列表文件。
思路:
1,对指定的目录进行递归。
2,获取递归过程所以的java文件的路径。
3,将这些路径存储到集合中。
4,将集合中的数据写入到一个文件中。
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;


public class JavaFileList {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws IOException{
		File dir = new File("E:\\学习\\黑马程序员JavaEE+Android——开学前自学的Java课程\\学习资料\\毕向东_Java基础源代码\\day20");
		List<File> list = new ArrayList<File>();
		fileToList(dir,list);
		
		File file = new File("javalist.txt");
		writeToFile(list,file.toString());
		

	}
	public static void fileToList(File dir,List<File> list){
		File[] files = dir.listFiles();
		for(File f : files){
			if(f.isDirectory()){
				fileToList(f,list);
			}
			else{
				if(f.getName().endsWith(".java"))
					list.add(f);
			}
			
		}
		
	}
	public static void writeToFile(List<File> list,String javalist)throws IOException{
		BufferedWriter bw = null;
		try{
			bw = new BufferedWriter(new FileWriter(javalist));
			for(File f:list){
				String path = f.getAbsolutePath();
				bw.write(path);
				bw.newLine();
				bw.flush();
			}
			
		}catch(IOException e){
			throw e;
			
		}
		finally{
			try{
				if(bw!=null){
					bw.close();
				}
			}catch(IOException e){
				throw e;
			}
		}
	}

}

Properties是hashtable的子类。
也就是说它具备map集合的特点。而且它里面存储的键值对都是字符串。


是集合中和IO技术相结合的集合容器。


该对象的特点:可以用于键值对形式的配置文件。


那么在加载数据时,需要数据有固定格式:键=值。

例子:

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Properties;
import java.util.Set;


public class PropertiesDemo {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		//method_1();
		loadDemo();
	}
	//将流中的数据加载到集合中去:
	public static void loadDemo() throws IOException{
		FileInputStream fis = new FileInputStream("info.txt");
		Properties pro = new Properties();
		pro.load(fis);
		pro.setProperty("wangwu","24");
		FileOutputStream fos = new FileOutputStream("info.txt");
		pro.store(fos, "ha");//将此 Properties 表中的属性列表(键和元素对)写入输出流。out - 输出流。comments - 属性列表的描述。 
		//PrintStream fs = new PrintStream(fos);
		pro.list(System.out);
		fis.close();
		fos.close();
		
		
		
	}
	//演示,如何将流中的数据存储到集合中。
	//想要将info.txt中键值数据存到集合中进行操作。
	/*
		1,用一个流和info.txt文件关联。
		2,读取一行数据,将该行数据用"="进行切割。
		3,等号左边作为键,右边作为值。存入到Properties集合中即可。

	*/
	public static void method_1() throws IOException{
		BufferedReader br = new BufferedReader(new FileReader("info.txt"));
		String len = null;
		Properties pro = new Properties();
		while((len = br.readLine())!=null){
			
			String arr[] = len.split("=");
			pro.setProperty(arr[0], arr[1]);
		}
		br.close();
		System.out.println(pro);
	}
	
	//设置和获取元素
	public static void setAndGet(){
		Properties pro = new Properties();
		pro.setProperty("zhangsan", "15");
		pro.setProperty("lisi", "25");
		String value = pro.getProperty("lisi");
		System.out.println("lisi"+"get"+value);
		Set<String> names = pro.stringPropertyNames();//获取所有键值
		for(String name : names){
			System.out.println(name+"   "+pro.getProperty(name));
		}
	}

}

练习:限制程序运行次数。当运行次数到达5次时,给出,请您注册的提示。并不再让该程序执行。

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


很容易想到的是:计数器。
可是该计数器定义在程序中,随着程序的运行而在内存中存在,并进行自增。
可是随着该应用程序的退出,该计数器也在内存中消失了。


下一次在启动该程序,又重新开始从0计数。
这样不是我们想要的。


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


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


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


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


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

import java.io.*;
import java.util.*;
class RunCount 
{
	public static void main(String[] args) throws IOException
	{
		Properties pro = new Properties();
		File file = new File("count.ini");
		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 = Integer.parseInt(value);
			if(count>5)
			{
				System.out.println("结束");
				return;
			}
		}
		count++;
		pro.setProperty("time",count+"");
		FileOutputStream fos = new FileOutputStream(file);
		pro.store(fos,"");

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

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


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

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

4,字符输出流,Writer。

例如:

import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class PrintStreamDemo {
	public static void main(String[] args) throws IOException {
		BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true);
		String line = null;
		while((line = buf.readLine())!=null){
			if("over".equals(line))
				break;
			out.println(line.toUpperCase());
		}
		out.close();
		buf.close();


	}

}

3.9合并流:

import java.io.*;
import java.util.*;
class SequenceDemo 
{
	public static void main(String[] args)throws IOException
	{
		Vector<FileInputStream> v = new Vector<FileInputStream>();
		v.add(new FileInputStream("a.txt"));
		v.add(new FileInputStream("b.txt"));
		v.add(new FileInputStream("c.txt"));
		Enumeration<FileInputStream> en = v.elements();
		SequenceInputStream sis = new SequenceInputStream(en);

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

文件的切割和合并:

import java.io.*;
import java.util.*;
class splitDemo 
{
	public static void main(String[] args) throws IOException
	{
		 //splitFile();
		 merge();
	}
	public static void merge()throws IOException
	{
		ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
		for(int x= 1;x<2;x++)
		{
			al.add(new FileInputStream("c:\\spliterfiles\\"+x+".part"));
		}
		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("c:\\2.jpg");
		byte[] buf = new byte[1024];
		int len = 0;
		while((len = sis.read(buf))!=-1)
		{
			fos.write(buf,0,len);
		}
		fos.close();
		sis.close();
	}
	public static void splitFile()throws IOException
	{
		FileInputStream fis = new FileInputStream("c:\\1.jpg");
		FileOutputStream fos=null;
		byte []buf = new byte[1024*1024];
		int len = 0;
		int count=1;
		while((len=fis.read(buf))!=-1)
		{
			fos = new FileOutputStream("c:\\spliterfiles\\"+(count++)+".part");
			fos.write(buf,0,len);
			fos.close();
		}
		fis.close();
	}
}
3.9操作对象:ObjectInputStream与ObjectOutputStream

被操作的对象需要实现Serializable接口(标记接口)

import java.io.*;
class Person implements Serializable//标记接口
{
	static final long serialVersionUID=42;//保证id号一致,为了序列化方便,新的类还能操作曾经被序列化的对象
	private String name;
	transient int age;//age也没有序列化(在堆内存存在,不在文件中存在)
	static String country="cn";//静态的不能被序列化。cn不会被传进来的数改变
	Person(String name,int age,String country)
	{
		this.name = name;
		this.age = age;
		this.country=country;
	}
	public String toString()
	{
		return name+"::"+age+":"+country;
	}
}
<pre name="code" class="java">import java.io.*;
class ObjectStreamDemo 
{
	public static void main(String[] args) throws Exception
	{
		//writeObject();
		readObj();
	}
	public static void readObj()throws Exception
	{
		ObjectInputStream ols = new ObjectInputStream(new FileInputStream("obj.txt"));
		Person p = (Person)ols.readObject();
		System.out.println(p);
	}
		public static void writeObject()throws Exception
	{
			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
			oos.writeObject(new Person("zhangsan",15,"kr"));
			oos.close();

	}
}


 4管道流:PipedInputStream和PipedOutputStream 

输入输出可以直接进行连接,通过结合线程使用

例如:

import java.io.*;


public class PipeDemo {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		PipedInputStream pi = new PipedInputStream();
		PipedOutputStream po = new PipedOutputStream();
		pi.connect(po);//连接!!!很重要
		Read r = new Read(pi);
		Write w = new Write(po);
		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 {
			byte[] b = new byte[1024];
			System.out.println("读取前数据没有阻塞");
			int len = in.read(b);
			System.out.println("读到数据。。。阻塞结束");
			String s = new String(b,0,len);
			System.out.println(s);
		} catch (IOException e) {
			throw new RuntimeException("管道流读取失败!");
		}
		
		
	}
	
}
class Write implements Runnable{
	private PipedOutputStream po;
	Write(PipedOutputStream po){
		this.po= po;
	}
	public void run() {
		try {
			System.out.println("开始写入数据");
			Thread.sleep(6000);
			po.write("管道来了".getBytes());
			po.close();
		} catch (Exception e) {
			throw new RuntimeException("管道写入失败");
		}
		
	}
	
}

4.RandomAccessFile
该类不是算是IO体系中子类。
而是直接继承自Object。
但是它是IO包中成员。因为它具备读和写功能。
内部封装了一个数组,而且通过指针对数组的元素进行操作。
可以通过getFilePointer获取指针位置,
同时可以通过seek改变指针的位置。
其实完成读写的原理就是内部封装了字节输入流和输出流。
通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式:只读r,,读写rw等。
如果模式为只读 r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。
如果模式rw。操作的文件不存在,会自动创建。如果存则不会覆盖。

程序:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;


public class RandomAccessFileDemo {
	public static void main(String[] args) throws IOException {
		//write();
		//read();
		writeFile_2();
	}
	//
	public static void writeFile_2() throws IOException{
		RandomAccessFile ra = new RandomAccessFile("fo.txt","rw");
		//ra.seek(8*3);
		ra.write("周期".getBytes());
		ra.writeInt(96);
		ra.close();
	}
	public static void read() throws IOException{
		RandomAccessFile ra = new RandomAccessFile("fo.txt","r");
		//调整对象中的指针
		//ra.seek(8);
		//跳过指定的字节数
		ra.skipBytes(8);//只能往后跳,不能往前跳
		byte b[] = new byte[4];
		ra.read(b);
		String name = new String(b);
		int age = ra.readInt();
		System.out.println("name"+name);
		System.out.println("age"+age);
		ra.close();
		
	}
	public static void write() throws IOException{
		RandomAccessFile ra = new RandomAccessFile("fo.txt","rw");
		ra.write("李四".getBytes());
		//ra.write(258);//这样会出错会去取最低8为,258的二进制数第一位的1就会被舍弃,就会出错
		ra.writeInt(97);
		ra.write("王五".getBytes());
		ra.writeInt(99);
		ra.close();

	}

}
操作基本数据类型:DataInputStream   DataOutputStream

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;


public class DataStreamDemo {
	public static void main(String[] args) throws IOException {
		writeData();
	<span style="white-space:pre">	</span>readData();
	}
	public static void readData() throws IOException{
		DataInputStream dis = new DataInputStream(new FileInputStream("dos.txt"));
		int num = dis.readInt();
		double s = dis.readDouble();
		Boolean a = dis.readBoolean();
		System.out.println("num:"+num);
		System.out.println("double:"+s);
		System.out.println("boolean:"+a);
		String ss = dis.readUTF();
		System.out.println(ss);
		dis.close();
	}
	public static void writeData() throws IOException{
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("dos.txt"));
		dos.writeInt(4);
		dos.writeDouble(3.2);
		dos.writeBoolean(true);
		dos.writeUTF("你好");
		dos.close();
	}
	

}

5.ByteArrayInputStream,  ByteArrayOutputStream

用于操作字节数组的流对象。
ByteArrayInputStream :在构造的时候,需要接收数据源,。而且数据源是一个字节数组。
ByteArrayOutputStream: 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。
这就是数据目的地。
因为这两个流对象都操作的数组,并没有使用系统资源。
所以,不用进行close关闭。
在流操作规律讲解时:

源设备,
键盘 System.in,硬盘 FileStream,内存 ArrayStream。
目的设备:
控制台 System.out,硬盘FileStream,内存 ArrayStream。

用流的读写思想来操作数据。


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;


public class ByteArrayDemo {
	public static void main(String[] args) throws IOException {
		ByteArrayInputStream bai = new ByteArrayInputStream("ABCDEFG".getBytes());
		ByteArrayOutputStream bao = new ByteArrayOutputStream();
		byte[] b = new byte[1024];
		int len = 0;
		while((len = bai.read(b))!=-1){
			bao.write(b,0,len);
		}
		System.out.println(bao.size());
		System.out.println(bao.toString());
		bao.writeTo(new FileOutputStream("a.txt"));
	}

}

5.字符编码:

5.1转换流的字符编码
字符编码:

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

通过子类转换流来完成:InputStreamReader  OutputStreamWriter,

在两个对象进行构造的时候可以加入字符集


编码的由来

计算机只能识别二进制数据,早起由来是电信号,为了方便应用计算机,让它可以识别各个国家的文字

就将各个国家的文字用数字来表示,并一一对应,形成一张表,这就是编码表

常见的编码表

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

ISO8859-1:拉丁码表。欧洲码表,用一个字节8位表示

GB2312:中国的中文编码表

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

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

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

举例:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;


public class EncodeDemo {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		write_encode();
		read_encode();

	}
	public static void read_encode() throws IOException{
		InputStreamReader is = new InputStreamReader(new FileInputStream("12.txt"),"unicode");
		char[] ch = new char[10];
		int len = 0;
		len = is.read(ch);
		String str = new String(ch,0,len);
		System.out.println(str);
		is.close();
	}
	public static void write_encode() throws IOException{
		OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream("12.txt"),"unicode");
		os.write("你好");
		os.close();
		
	}

}

字符编码:

编码:字符串变成字节数组   String--->byte[];  str.getBytes(charseName);

解码:字节数组变成字符串  byte[]--->String: new String(byte[],charaseName);

举例子说明:

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;


public class EncodeDemo2 {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		String s = "你好";
		//编码
		byte b1[] = s.getBytes("GBK");
		System.out.println(Arrays.toString(b1));
		//解码
		String s1 = new String(b1,"ISO8859-1");
		System.out.println(s1);
		//出现编码错误,但对应的编码数字是一样的,所以再次取出进行再一次编码解码
		
		byte b2[] = s1.getBytes("ISO8859-1");
		System.out.println(Arrays.toString(b2));
		//解码
		String s2 = new String(b1,"GBK");
		System.out.println(s2);
		

	}

}

特殊字符编码问题,------联通

新建文本文件,保存"你好",然后打开改为"联通",保存后就变了!

用GBK解码,2个字节一查,但是原本编码是按照utf-8来编码的,有的2个,有的3个一查,所以可能会出现错误,这时候就会有utf-8的标识头。
分析: 因为联通的二进制编码正好符合了utf-8的编码了。解决办法,在记事本中写联通时,先写其他字再加上联通就没问题了。


















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值