黑马程序员--------java IO流 File类、Properties、打印流、合并流、对象序列化、随机读写、字符编码

-----------android培训java培训、java学习型技术博客、期待与您交流!------------


File类

 

1、用来将文件或者文件夹封装成对象, 方便对文件与文件夹的属性信息进行操作, File对象可以作为参数传递给流的构造函数

    //a.txt封装成File对象,可以将已有的和未出现的文件或者文件夹封装成对象

    File f1 = newFile(“a.txt”); //打印f1时打印的是a.txt , 是相对路径

    //将文件的父目录和文件一起封装成对象

    File f2 = newFile(“c:\\abc”,b.txt); 打印f2时打印的是c:\abc”\b.txt, 绝对路径。

    //将文件父目录或者子目录作为参数传递到文件对象

    File d = newFile(“c:\\abc”);

    File f3 = newFile(d,”c.txt”); //与上一种方式是一样的,只是写法不同

    //\\目录分隔符使用跨平台的方式的写法:File.separator

    File f4 = newFile(“c:”+File.separator+”abc”+File.separator+”a.txt”);


2、File类中的常用方法

1)创建

     boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false和输出流不一样,输出流对象建立创建文件。而且文件已经存在,会覆盖

      boolean mkdir():创建文件夹

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

2)删除

     boolean delete();删除失败返回false

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

3)判断

     boolean exists():文件是否存在。在流读取文件时可以先判断文件是否存在,这就是将文件封装成对象的好处

     isFile():是否是文件

     isDirectory();是否是目录

      isHidden();是否隐藏

     isAbsolute();//判断文件是否为绝对路径,如果是文件不存在也会返回true

     注意:记住在判断文件对象是否是文件或者目录时,必须先判断该文件是否存在,通过exists判断

4)获取信息

      getName();获取文件名称

     getPath();获取相对路径,封装什么路径获取什么路径

     getParent();获取父目录  该方法返回的是绝对路径下的父目录,如果文件是相对路径则返回null 如果相对路径中有上一层目录,该目录就是返回结果

     getAbsolutePath();获取绝对路径

      long lastModified();最后一次修改时间

      long length();文件大小

5)其他

     File[] listRoots:获取系统有效根盘符

     String[] list:获取指定目录下的所有文件和文件夹的名称,包含隐藏的。调用list方法的File对象必须是封装了的一个目录,必须存在

     File[] listFiles:返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录一般用File[] listFiles比较多

 

3、递归:就是函数自身调用自身,简单说就是功能内部又用到该功能,但传递的参数值不确定。在使用递归是一般要单独定义一个方法

   注意事项:一定要定义递归的条件;递归的次数不要过多,否则会出现StackOverflowError栈内存溢出错误,原因是递归时,在栈内存不断创建对象方法,只有最里面的方法执行完才会执行外边的

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

思路:因为要找到目录下的所有文件,就要使用递归操作
      获取文件的绝对路径,存储到一个集合中
      遍历集合,通过流写入方式将文件的绝对路径存储到一个文件中
*/
import java.util.*;
import java.io.*;
class  Demo3
{
	public static void main(String[] args) 
	{
		ArrayList<String> list = new ArrayList<String>();
		File dir = new File("e:\\java0217");
		filePath(dir,list);
		System.out.println(list.size());//打印集合中是否有元素
		File f = new File(dir,"FileDirectory.txt");//新建文件对象,作为写入流的目的地
		writeToFile(list,f);
	}
	public static void filePath(File dir,ArrayList<String> list)
	{
		File[] files = dir.listFiles();
		for(File file : files)
		{
			if(file.isDirectory())//判断是否为文件夹,是递归调用
				filePath(file,list);
			else
			{
				if(file.getName().endsWith(".java"))//获取文件名称的后缀名是不是.jaja文件
				{
					String path = file.getAbsolutePath();//获取找到的文件的绝对路径
					list.add(path);//将绝对路径存入集合
				}		
			}
		}
	}
	public static void writeToFile(ArrayList<String> list,File f)
	{
		
		BufferedWriter bw = null;
		try
		{
			bw = new BufferedWriter(new FileWriter(f));
			for(String file : list)
			{
				bw.write(file);
				bw.newLine();
				bw.flush();
			}
		}
		catch (IOException e)
		{
			throw new RuntimeException("写入文件失败");
		}
		finally
		{
			try
			{
				if(bw!=null)
					bw.close();
			}
			catch (IOException e)
			{
				throw new RuntimeException("关闭流失败");
			}
		}		
	}
}


java.util.Properties:是集合中和io技术相结合的容器

1、properties 是hashtable 的子类,也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串,可以用于键值对形式的配置文件,那么在加载数据时,需要数据有固定格式:键=

2、常见方法:

   *getProperties(String key):获取值

   *setProperties(String key,String value)://设置值

   *load(InputStream inStream); //从字节输入流中读取属性列表(键和元素对)

   *load(Reader reader); //从字符输入流中读取属性列表(键和元素对)

   *store(OutputStream out , String comments); //将此 Properties 表中的属性列表(键和元素对)写入字节输出流,comments为描述信息。例如haha

   *store(Writer wri ,String comments; //将此 Properties 表中的属性列表(键和元素对)写入字符输出流

import java.util.*;
import java.io.*;
class PropertiesDemo
{
	public static void main(String[] args)throws IOException 
	{
		//setAndGet();
		//method();//模拟properties中的load方法
		fileLoad();
	}
	public static void fileLoad()throws IOException
	{
		Properties prop = new Properties();
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("Info.txt"));
		prop.load(bis);
		prop.setProperty("lisi","21");
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Info.txt"));
		prop.store(bos,"haha");
		System.out.println(prop);
		bis.close();
		bos.close();
	}
	/*
	演示,如何将流中的数据存储到集合中
	要求:将Info.txt中键值数据存储到集合中
	1、用一个流和Info.txt相关联
	2、读取一行数据,将该行数据用“=”进行切割
	3、等号左边作为键,右边作为值。在存入properties集合中即可
	*/
	public static void method()throws IOException
	{
		BufferedReader br = new BufferedReader(new FileReader("Info.txt"));
		Properties prop = new Properties();
		String line =null;
		while((line=br.readLine())!=null)
		{
			String[] str = line.split("=");
			prop.setProperty(str[0],str[1]);
		}
		br.close();
		System.out.println(prop);
	}
	//设置和获取元素 
	public static void setAndGet()
	{
		Properties prop = new Properties();
		prop.setProperty("zhangsan","33");
		prop.setProperty("lisi","50");
		String value = prop.getProperty("lisi");
		//System.out.println(value);
		prop.setProperty("lisi","20");
		Set<String> names = prop.stringPropertyNames();
		for(String name : names)
		{
			System.out.println(name+"::"+prop.getProperty(name));
		}
	}
}

/*
用于记录应用程序运行次数
如果使用次数已到,那么给出注册提示。
思路:
1、使用硬盘上的配置文件记录软件运行次数,配置文件以键值形式存储 要使用到Map集合
2、必须通过输入流的方式来关联配置文件,要使用到IO
3、这样就可以使用集合与IO的集合技术  Properties
4、程序没运行一次需要一个计数器加一次,在存回配置文件 使用输出流
*/
import java.util.*;
import java.io.*;
class Demo55 
{
	public static void main(String[] args) throws IOException
	{
		method();
	}
	public static void method()throws IOException
	{
		File f = new File("protect.ini");//将文件封装成对象
		if(!f.exists())
			f.createNewFile();//不存在就创建
		BufferedReader br = new BufferedReader(new FileReader(f));
		Properties prop = new Properties();
		prop.load(br);
		int count=0;
		String value = prop.getProperty("time");
		if(value!=null)
		{
			count = Integer.parseInt(value);
			if(count>=5)
				System.out.println("使用期限已到,请注册");
			count++;
		}
		else
		{
			count =1;
		}
		prop.setProperty("time",count+"");
		FileWriter fw = new FileWriter(f);
		prop.store(fw,"heihei");
		br.close();
		fw.close();
	}	
}

printStream:打印流

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

2、分类:字节打印流PrintStream  和字符打印流 PrintWriter

3、字节打印流:PrintStream  构造函数可以接收的参数类型:

1)file对象。File

2)字符串路径。String

3)字节输出流。OutputStream

 

4、PrintWriter字符打印流:推荐使用字符打印流,功能齐全 。构造函数可以接收的参数类型:

1file对象。File

2)字符串路径。String

3)字节输出流。OutputStream

4)字符输出流。Writer

//打印流  PrintWriter
import java.io.*;
class Demo6
{
	public static void main(String[] args)throws IOException 
	{
		method();
	}
	public static void method()throws IOException
	{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter pw = new PrintWriter(new FileWriter("a.txt"),true);//加上true实现自动刷新
		String line=null;
		while((line=br.readLine())!=null)
		{
			if(line.equals("end"))
				break;
			pw.println(line.toUpperCase());
		}
		br.close();
		pw.close();
	}
}

SequenceInputStream:合并流

1、将其他输入流关联的文件对象进行逻辑串联,它从输入流的有序集合开始,从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流文件的末尾为止,将多个输入流合并成一个输入流,实现数据的合并

2、好处:可以更方便的操作多个读取流,其实这个序列流内部会有一个有序集合容器,用于存储多个输入流对象

3、该对象的构造函数参数是枚举,想要获取枚举,需要Vector集合,但是Vector集合效率低。可以使用ArrayList集合,但是ArrayList集合只有迭代,因为枚举是一个接口,可以使用匿名内部类的方式创建枚举对象,复写hasMoreElements()nexElement()着两个方法。然后分别返回ArrayList集合迭代器的it.hasNext()it.nex(),在将枚举传递给Sequence的构造函数

4、合并原理:多个读取流对应一个输出流

   切割原理:一个读取流对应多个输出流

import java.io.*;
import java.util.*;
class Demo8 
{
	public static void main(String[] args)throws IOException 
	{
		//splitFile();
		sequence();
	}
	public static void splitFile()throws IOException//切割图片
	{
		FileInputStream fis = new FileInputStream("e:\\java0217\\day20\\10.bmp");
		FileOutputStream fos = null;
		byte[] buf = new byte[1024*1024];//每次读取一兆数据存储到数组
		int len = 0;
		int x =1;
		while((len=fis.read(buf))!=-1)
		{
			fos = new FileOutputStream("e:\\java0217\\day20\\splitFile\\"+(x++)+".part");
			fos.write(buf,0,len);
			fos.close();
		}
		fis.close();
	}
	public static void sequence()throws IOException//合并图片
	{
		//因为要用到Enumeration,可以使用Vector。由于Vector是同步的,效率低,所以用ArrayList
		//但是ArrayList只有迭代器,只能使用匿名内部类的方式,复写Enumeration的方法,返回ArrayList的元素
		ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
		for(int x=1;x<=5;x++)
		{
			al.add(new FileInputStream("E:\\java0217\\day20\\splitFile\\"+x+".part"));
		}
		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("E:\\java0217\\day20\\splitFile\\pic.jpg");
		byte[] buf = new byte[1024];
		int len =0;
		while((len=sis.read(buf))!=-1)
		{
			fos.write(buf);
		}
		sis.close();
		fos.close();
	}
}

对象的序列化

1、java.io.ObjectOutputStream:将 Java 对象的基本数据类型和图形写入 OutputStream,可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。

2、java.io.ObjectInputStream

//对象的序列化
//ObjectOutputStream序列化和ObjectInputStream 反序列化

import java.io.*;
class ObjectStreamDemo1 
{
	public static void main(String[] args) throws Exception
	{
		//writeObj();
		readObj();
	}
	public static void writeObj()throws IOException//ObjectOutputStream 写入的基本数据和对象进行序列化
	{
		FileOutputStream fos = new FileOutputStream("obj.txt");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(new Person("lisi",22));//使用 ObjectOutputStream 将对象写入文件
		oos.close();
	}	
	public static void readObj()throws Exception//ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化
	{
		FileInputStream fis = new FileInputStream("obj.txt");
		ObjectInputStream ois = new ObjectInputStream(fis);
		Person p = (Person)ois.readObject();//从 ObjectInputStream 读取对象
		System.out.println(p);
	}
}
class Person implements Serializable//只有实现Serializable接口对象才能被序列化和反序列化,它只是对象序列化的一个标记接口
{
	public static final long serialVersionUID = 40L;//可序列化类显式声明 serialVersionUID
	private String name;
	transient int age;//transient 可以用来声明age不能被序列化,age只存在于对内存中
	Person(String name,int age)
	{
		this.name=name;
		this.age=age;
	}
	public String toString()
	{
		return name+":"+age;
	}
}<strong>
</strong>

RandomAccessFile随机读写访问

1、随机访问文件,自身具备读写的方法

2、通过skipBytes(intx),seek(int x)来达到随机访问,该类不算是io体系中子类,而是直接继承Object,但是它是io包中的成员,因为它具备读和写功能,内部封装了一个数组,而且通过指针对数组的元素进行操作。可以同getFilePointer获取指针位置,同时可以通过seek改变指针的位置

    其实完成读写的原理就是内部封装了字节输入、输出流。

    通过构造函数可以看出,该类只能操作文件,而且文件还有模式 r读 rw读写

    如果模式为读r,不会创建文件,会去读取一个已存在的文件,如果该文件不存在,则会出现异常

    如果模式为读取 rw,要操作的文件不存在,会自动创建,如果存在就不会被覆盖

import java.io.*;
class RandomAccessFileDemo
{
	public static void main(String[] args)throws IOException 
	{
		write();
		read();
	}
	public static void write()throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("a.txt","rw");
		raf.write("张三".getBytes());
		raf.writeInt(97);

		raf.write("李四".getBytes());
		raf.writeInt(99);
		raf.seek(8*3);//在指定的指针位置写入数据
		raf.write("赵六".getBytes());
		raf.writeInt(108);
	}
	public static void read()throws IOException
	{
		RandomAccessFile raf = new RandomAccessFile("a.txt","r");
		raf.seek(8*3);//改变指针位置,可以直接获取赵六信息
		byte[] buf = new byte[4];//一个汉字两个字节
		int len = raf.read(buf);
		String name = new String(buf);
		int age = raf.readInt();//readInt一次读取一个整数
		System.out.println(name+"..."+age);
	}
}


DataStream操作基本数据的字节流对象

DataInputStream和DataOutputStream

//DataStream操作基本数据的流对象
//DataInputStream DataoutputStream
import java.io.*;
class DataStream 
{
	public static void main(String[] args)throws IOException 
	{
		//writeData();
		//readData();
		writeUTF();
		readUTF();
	}
	public static void writeData()throws IOException
	{
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
		dos.writeInt(3030);
		dos.writeBoolean(true);
		dos.writeDouble(123.456);
		dos.close();
	}
	public static void readData()throws IOException
	{
		DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
		int i = dis.readInt();//读取是要按照写入是的顺序进行读取,否则数据不正确
		boolean b = dis.readBoolean();
		double d = dis.readDouble();
		System.out.println(i);
		System.out.println(b);
		System.out.println(d);
		dis.close();
	}
	public static void writeUTF()throws IOException //对UTF解码是只能用其对应的方法
	{
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("UTF.txt"));
		dos.writeUTF("哈哈");
		dos.close();
	}
	public static void readUTF()throws IOException
	{
		DataInputStream dis = new DataInputStream(new FileInputStream("UTF.txt"));
		String str = dis.readUTF();
		System.out.println(str);
		dis.close();
	}
}

ByteArrayStream操作字节数组的流

ByteArrayInputStream和ByteArrayOutputStream

/*
ByteArrayStream:用于操作字节数组的流对象
ByteArrayInputStream:在构造时,需要接受数据源,而且数据源是以个字节数组
ByteArrayoutputStream:在构造时,不用定义数据目的,因为该对象中内部封装了可变长度的字节数组,就是数据的目的地

因为这两个流对象都操作的数组,并没有使用系统资源,所以不需要进行close关闭

流操作规律讲解时:
原设备:
   键盘 System.in  硬盘 FileStream  内存 ArrayStream
目标设备:
   控制台 System.out 硬盘FileStream  内存 ArrayStream
*/
import java.io.*;
class ByteArrayStream 
{
	public static void main(String[] args) 
	{
		//数据源
		ByteArrayInputStream bis = new ByteArrayInputStream("abcdefg".getBytes());
		//数据目的
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		int by =0;
		while((by=bis.read())!=-1)
		{
			bos.write(by);
		}
		System.out.println(bos.size());
		System.out.println(bos.toString());
	}
}

CharArrayStream操作字符数组的流

CharArrayReader和CharArrayWrite

StringStream操作字符串的流

StringReader和StringWriter


字符编码:

/*
转换流的字符编码
*/
import java.io.*;
class EncodeStream 
{
	public static void main(String[] args)throws IOException 
	{
		//writeFile();
		readFile();
	}
	public static void writeFile()throws IOException
	{
		//使用指定编码表往文件中写入数据,使用转换流
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf.txt"),"utf-8");
		osw.write("你好");
		osw.close();
	}
	public static void readFile()throws IOException
	{
		//读取时应该指定与写入时同一个编码表,否则会出现不是想要的结果
		InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"),"gbk");//(new FileInputStream("utf.txt"),"utf-8")
		char[] ch = new char[10];
		int x = isr.read(ch);
		String str = new String(ch,0,x);
		System.out.println(str);
		isr.close();
	}
}
/*
编码:字符串变字节数组

解码:字节数组变字符串

String-->byte[];   str.getbytes(charsetName);

byte[]-->String;   new String(byte[],charsetName);

tomCat服务器就是默认的iso8859-1码表,在向它发送gbk编码时,要在服务端先编码一次在解码一次
注意:如果使用的是gbk编码,用的是utf-8进行解码,这时就不能将utf-8解码数据进行utf-8编码,因为这样获取
      不到原先的编码,原因是gbk和utf-8都支持中文,一个是2字节一个是3字节
*/
import java.util.*;
class  EncodeDemo
{
	public static void main(String[] args) throws Exception
	{
		String str = "你好";
		byte[] by1 = str.getBytes("gbk");
		System.out.println(Arrays.toString(by1));
		String s1 = new String(by1,"iso8859-1");//当解码误使用了iso8859-1,会得带一个错误的结果
		System.out.println(s1);                 
		byte[] by2 = s1.getBytes("iso8859-1");//这时可以对这个字符串在进行一次iso8859-1编码获取原先的编码
		System.out.println(Arrays.toString(by2));
		String s2 = new String(by2,"gbk");//将获取到的编码再用gbk进行解码
		System.out.println(s2);
	}
}

总结练习:

/*
有5个学生,每个学生有三门课的成绩,从键盘输入一下数据(姓名加三门课成绩),
输入的格式:如:zhangsan,30,40,50计算出总成绩,并把学生的信息和计算出来的
总成绩由高到低存放在磁盘文件“stud.txt”中

思路:1、创建一个学生类,描述学生信息,让学生类具备比较性或定义比较器进行排序
      2、读取录入信息,使用切割方法对录入信息按逗号进行切割,再存入一个可以排序的集合TreeSet
	  3、取出集合元素,存入硬盘目标地址
*/
import java.io.*;
import java.util.*;
class Student //implements Comparable<Student>
{
	private String name;
	private int sum;
	private int ch;
	private int math;
	private int english;
	Student(String name,int ch,int math,int english)
	{
		this.name=name;
		this.ch=ch;
		this.math=math;
		this.english=english;
		sum = ch+math+english;
	}
	/*public int compareTo(Student s)
	{
		
		if(this.sum>s.sum)
			return 1;zhangsan,30,40,50
		if(this.sum==s.sum)
			return this.name.compareTo(s.name);
		else
			return -1;
	}*/
	public String getName()
	{
		return name;
	}
	public int getSum()
	{
		return sum;
	}
	public String toString()
	{
		return name+":"+ch+","+math+","+english;
	}

	
}
class Com implements Comparator<Student>//自定义比较器,优先按总分排序,总分一样按年龄自然顺序排
{
	
	public int compare(Student s1,Student s2)
	{
		if(s1.getSum()>s2.getSum())
			return 1;
		if(s1.getSum()==s2.getSum())
			return s1.getName().compareTo(s2.getName());
		else
			return -1;
	}
}
class WriteInfo
{
	public static void method()throws IOException
	{
		Comparator<Student> cp = Collections.reverseOrder(new Com());//反转比较器,实现由大到小排序

		TreeSet<Student> ts = new TreeSet<Student>(cp);//定义TreeSet集合来存储输入的数据,用于数据的排序

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//定义键盘输入

		File addr = new File("stud.txt");//将目标地址封装为一个文件对象
		if(! addr.exists())
			addr.createNewFile();
		PrintWriter pw = new PrintWriter(addr);
		String line = null;
		while((line=br.readLine())!=null)
		{
			if(line.equals("end"))
				break;
			String[] str = line.split(",");//将键盘输入的数据用逗号进行切割,再存储到集合
			ts.add(new Student(str[0],Integer.parseInt(str[1]),Integer.parseInt(str[2]),Integer.parseInt(str[3])));
		}
		//遍历排好序的集合,将集合数据取出使用字符打印流将数据打印到目的地
		Iterator<Student> it = ts.iterator();
		while(it.hasNext())
		{
			Student stu = it.next();
			//System.out.println(stu.toString());
			pw.print(stu.toString()+"\t");
			pw.println(stu.getSum()+"");
		}
		br.close();
		pw.close();
	}
}
class  Test
{
	public static void main(String[] args) throws IOException
	{
		 WriteInfo.method();
	}
}


----------- android 培训 java培训 、java学习型技术博客、期待与您交流!------------


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值