黑马程序员——Java基础---IO(二)--File类、Properties类、打印流、序列流、其他类

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

第一讲   File类
一、概述
1、File类:文件和目录路径名的抽象表示形式。
2、特点:
1)用来将文件或者文件夹封装成对象
2)方便对文件与文件夹的属性信息进行操作 。
3)File对象可以作为参数传递给流的构造函数。
4) File 类的实例是不可变的;也就是说,一旦创建, File 对象表示的抽象路径名将永不改变。
二、File对象创建
方法一:
File file = new File("a.txt");
将a.txt封装成file对象。可以将已有的和为出现的文件或者文件夹封装成对象。
方法二:
File file = new File("c:\\abc","b.txt");
将文件所在目录和文件一起传入,指定文件路径。
方法三:
File d = new File("c:\\abc");
File f
ile = new File(d,"c.txt");
将文件目录封装成对象,再创建文件对象。
三、File中常见的方法
1、创建
boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。
和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。
boolean mkdir():创建文件夹。
boolean mkdirs():创建多级文件夹。
2、删除
boolean delete():删除失败返回false。如果文件正在被使用,删除不了返回false。
void deleteOnExit();在程序退出时删除指定文件。
3、判断
boolean exists() :文件是否存在.
isFile():是否是一个标准文件
isDirectory();是否是目录
isHidden();是否被隐藏
isAbsolute();
 是否是绝对路径
4、获取信息
getName():获取文件名
getPath():获取路径
getParent():获取父级目录
getAbsolutePath() 获取绝对路径
long lastModified() 返回文件最后一次被修改的时间
long length() 
文件的长度
5、列出文件及过滤
File[] listFiles():返回一个抽象路径名数组
String[] list():返回字符串数组,表示目录中的文件和目录
File[] listFiles(FilenameFilter filter):返回抽象路径名数组,列出满足指定过滤器的文件和目录。
FilenameFilter:文件名过滤器,是一个接口,包含一个方法accept(),boolean accept(File dir,String name),对不符合条件的文件名过滤。
static File[] listRoots:列出可用的文件系统根。
String [] list(FilenameFilter filter):返回一个字符串数组,表示的目录中满足指定过滤器的文件和目录。
File[] listFiles(FileFilter filter):返回抽象路径名数组,目录中满足指定过滤器的文件和目录。
示例:
/*
需求:
通过String[] list(FilenameFilter filter)方法获取一个目录中所有的.java文件,其他文件都被过滤掉。
思路:
用匿名内部类传入一个filter对象
复写FilenameFilter接口的accept(File dir,String name)方法,并判断是否是.java文件
遍历数据,得到所有.java文件
*/
import java.io.*;

class  FilterDemo
{
	public static void main(String[] args) 
	{
		listDemo();
		
	}
	//获取一个指定目录中的所有.java文件的方法
	public static void listDemo()
	{
		File dir = new File("d:\\java01\\day19");
		//创建FilenameFilter匿名内部类,创建filter对象
		String[] arr = dir.list(new FilenameFilter()
		{
			public boolean accept(File dir,String name)
			{
				return name.endsWith(".java");判断文件名是否是.java结尾并返回
			}
		});


		System.out.println("len:"+arr.length);
		//遍历数组
		for(String name : arr)
		{
			System.out.println(name);
		}
	}

四、递归
1、定义
 函数每一次循环都可以调用本身功能来实现,即函数自身调用自身,这种表现形式,或者编程手法,称为递归。
2、递归注意:
a、限定条件。用来结束循环调用,否则会成死循环。
b、递归的次数。避免内存溢出。因为每次调用自身时都用先执行下一次调用自身的方法,不断在栈内存中开辟控件,越来越多,导致内存溢出。
示例一
/*需求:
列出指定目录下文件或者文件夹,包含子目录中的内容。也就是列出指定目录下所有内容。
思路:
因为目录中还有目录,只要使用同一个列出目录功能的函数完成即可。
在列出过程中出现的还是目录的话,还可以再次调用本功能。
所以用递归来实现。
*/
import java.io.*;

class RecursionDemo 
{
	public static void main(String[] args) 
	{	//关联指定路径
		File dir = new File("d:\\test");
		//列出关联路径中的所有.java文件
		showDir(dir,0);

	}
	
	public static String getLevel(int level)
	{
		StringBuilder sb = new StringBuilder();
		sb.append("|--");
		//每一级目录用指定字符连接
		for(int x=0; x
示例二
/*
删除一个带内容的目录。
删除原理:
在window中,删除目录从里面往外删除的。

既然是从里往外删除。就需要用到递归。
*/
import java.io.*;
class  RemoveDir
{
	public static void main(String[] args) 
	{
		//指定目录
		File dir = new File("d:\\testdir");        //删除目录
		removeDir(dir);
	}

	public static void removeDir(File dir)
	{
		File[] files = dir.listFiles();//列出目录下所有文件和目录
		
		for(int x=0; x
示例三
/*
练习
将一个指定目录下的java文件的绝对路径,存储到一个文本文件中。
建立一个java文件列表文件。

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

*/
import java.io.*;
import java.util.*;
class  JavaFileList
{
	public static void main(String[] args) throws IOException
	{
		//指定目录
		File dir = new File("d:\\java01");
		//定义一个list集合,存储.java文件的file对象
		List list = new ArrayList();
		//调用获取文件路径的方法
		fileToList(dir,list);
		//指定写入文件
		File file = new File(dir,"javalist.txt");
		//调用写入文件方法
		writeToFile(list,file.toString());

		


	}
	//获取指定文件夹中的所有.java文件的绝对路径,存入集合中
	public static void fileToList(File dir,List list)
	{
		File[] files = dir.listFiles();

		for(File file : files)
		{	//如果是目录继续获取
			if(file.isDirectory())
				fileToList(file,list);
			else
			{	//将.java文件的路径存入
				if(file.getName().endsWith(".java"))
					list.add(file);
			}
		}
	}
	//将集合中的元素写入到一个文件中
	public static void writeToFile(List list,String javaListFile)throws IOException
	{
		BufferedWriter bufw =  null;
		try
		{	//字符流缓冲区关联写入的文件
			bufw = new BufferedWriter(new FileWriter(javaListFile));
			
			for(File f : list)
			{
				String path = f.getAbsolutePath();
				bufw.write(path);//写入
				bufw.newLine();//换行
				bufw.flush();//刷新
			}

		}
		catch (IOException e)
		{
			throw new RuntimeException("写入文件失败");
		}
		finally
		{	//关闭资源
			try
			{
				if(bufw!=null)
					bufw.close();
			}
			catch (IOException e)
			{
				throw new RuntimeException("关闭失败");
			}
		}
	}
}

第二讲   Properties类

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

二、Properties的方法
1、设置
Object  setProperty(String key,String value);设置键和值,调用Hashtable的put方法。
2、获取
String getProperty(String key);用指定的key搜索value
3、操作流的方法
void load(InputStream is);从输入流中读取属性列表。
void  load(Reader reader);按简单的面向行的格式从输入字符流中读取属性列表。
void list(PrintStream out);将属性列表输出到指定的输出流。
void list(PrintWriter out);将属性列表输出到指定的输出流。
void store(OutputStream out,String comments);对应load(InputStream) 方法,将属性列表(键和元素对)写入输出流。comments是属性列表的描述。
void store(Writer writer,String comments);对应load(Reader)方法,将属性列表(键和元素对)写入输出字符。
示例
/*如何将流中的数据存储到集合中。
想要将info.txt中键值数据存到集合中进行操作。
思路:
1,用一个流和info.txt文件关联。
2,读取一行数据,将该行数据用"="进行切割。
3,等号左边作为键,右边作为值。存入到Properties集合中即可。

*/
//将文件数据存储进Properties集合的方法
public static void method() throws IOException
{	//使用字符读取缓冲流关联文件
	BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));

	String line = null;
	//定义Properties集合
	Properties prop = new Properties();


	while((line=bufr.readLine())!=null)
	{
		String[] arr = line.split("=");
		//将键和值存入
		prop.setProperty(arr[0],arr[1]);
	}

	bufr.close();//关闭流

	System.out.println(prop);
}



//设置和获取元素。
public static void setAndGet()
{
	Properties prop = new Properties();

	prop.setProperty("zhangsan","30");
	prop.setProperty("lisi","39");
	String value = prop.getProperty("lisi");
	prop.setProperty("lisi",89+"");

	Set names = prop.stringPropertyNames();
	for(String s : names)
	{
		System.out.println(s+":"+prop.getProperty(s));
	}
}

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

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

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

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

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

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

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

配置文件可以实现应用程序数据的共享。
*/
mport 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)//如果使用次数超过5次,则禁止再使用
			{
				System.out.println("您好,使用次数已到,请充值后再使用!");
				return ;
			}

		}

		count++;//每使用一次自增

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

		FileOutputStream fos = new FileOutputStream(file);

		prop.store(fos,"");

		fos.close();//关流
		fis.close();//返回程序使用的次数
		
	}
}

第三讲   打印流

一、概述
1,、打印流包括:字节打印流(PrintStream)、字符打印流(PrintWriter)。
2、该流提供了打印方法,可以将各种数据类型的数据都原样打印。
二、字节打印流
构造函数可以接收的参数类型:
1
file对象。File
2
字符串路径。String
3
字节输出流。OutputStream
三、字符打印流
构造函数可以接收的参数类型:
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));
                //打印流关联文件,自动刷新
		PrintWriter out = new PrintWriter(new FileWriter("a.txt"),true);

		String line = null;

		while((line=bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;//定义结束标识
			out.println(line.toUpperCase());
			//out.flush();
		}
                //关流
		out.close();
		bufr.close();

	}	
}

第四讲   序列流

一、概述
1、SequenceInputStream对多个流进行合并。也称为合并流
2、构造函数
SequenceInputStream(InputStrean s1,InputStream s2); 通过记住这两个参数来初始化新创建的SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此SequenceInputStream 读取的字节。
二、合并多个流步骤
1、创建集合,并将流对象添加进集合。
2、创建Enumeration对象,将集合元素加入。
3、创建SequenceInputStream对象,合并流对象。
4、创建写入流对象,FileOutputStream对象,关联文件。
5、利用SequenceInputStream对象和FileOutputStream对象对数据进行反复读写操作。
示例
/*需求
将三个文本文件中的数据合并到一个文件中
思路:
创建一个Vector集合,将三个文本文件字节流添加到集合中
创建Enumeration对象,创建SequenceInoutStream对象关联Enumeration对象
输出流关联新文本文件
反复读写*/
import java.io.*;
import java.util.*;
class SequenceDemo 
{
	public static void main(String[] args) throws IOException
	{

		Vector v = new Vector();//创建Vector对象,并添加流对象

		
		v.add(new FileInputStream("d:\\1.txt"));
		v.add(new FileInputStream("d:\\2.txt"));
		v.add(new FileInputStream("d:\\3.txt"));

		Enumeration en = v.elements();//创建枚举对象

		SequenceInputStream sis = new SequenceInputStream(en);

		FileOutputStream fos = new FileOutputStream("d:\\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();

	}
}

练习
/*切割文件
需求:讲一个jpg文件按1M大小切割成几部分
思路:
使用文件字节流关联jpg文件
定义一个容器存储1M大小的数据,存满后,写入新文件
*/

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

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

	//将部分文件合并为一个可使用的文件
	public static void merge()throws IOException
	{	//定义一个集合存储被切割的这些部分文件数据
		ArrayList list = new ArrayList();

		for(int x=1; x<=3; x++)
		{
			al.add(new FileInputStream("d:\\splitfiles\\"+x+".part"));
		}

		final Iterator it = al.iterator();
		//为了提高效率,创建Enumeration匿名内部类
		Enumeration en = new Enumeration()
		{
			public boolean hasMoreElements()
			{
				return it.hasNext();
			}
			public FileInputStream nextElement()
			{
				return it.next();
			}
		};
		//关联枚举对象
		SequenceInputStream sis = new SequenceInputStream(en);

		//将合并的文件数据写入指定文件
		FileOutputStream fos = new FileOutputStream("d:\\splitfiles\\科比.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("d:\\科比.jpg");

		FileOutputStream fos = null;

		//定义1M大小的容器
		byte[] buf = new byte[1024*1024];

		int len = 0;
		int count = 1;
		while((len=fis.read(buf))!=-1)
		{	//读取满1M就写入一个文件
			fos = new FileOutputStream("d:\\splitfiles\\"+(count++)+".part");
			fos.write(buf,0,len);
			fos.close();//写完一部分数据后关流
		}
		//关流
		fis.close();	
	}
}

第五讲   其他类

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

示例
class RandomAccessFileDemo 
{
	public static void main(String[] args) throws IOException
	{
		//writeFile_2();
		readFile();

	}

	public static void readFile()throws IOException
	{      //创建RandomAccessFile对象
		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();
	}
}

二、管道流
1、PipedInputStream和PipedOutputStream
2、输入输出可以直接进行连接,通过结合线程使用。
3、方法connect(PipedOutputStream src) 使此管道输入流连接到管道输出流 src
示例
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];

			System.out.println("读取前。。没有数据阻塞");
			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("管道读取流失败");
		}
	}
}
//写操作
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("piped lai la".getBytes());
			out.close();
		}
		catch (Exception 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();


	}
}

三、DataInputStream和DataOutputStream
1、可以用于操作基本数据类型的数据的流对象。
2.、常用方法:
String readUTF();读入一个已使用UTF-8修改版格式编码的字符串。
void writeUTF(String s);将表示长度信息的两个字节写入输出流,后跟字符串 s 中每个字符的 UTF-8修改版表示形式。
int skipBytes();在输入流中跳过数据的 n 个字节,并丢弃跳过的字节。
以及对基本数据类型读入输入流和写入输出流
示例
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"));
		//用UTF-8修改版格式编码读取字符串
		String s = dis.readUTF();

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



	public static void writeUTFDemo()throws IOException
	{
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("utfdate.txt"));
		//用UTF-8修改版格式编码写入字符串
		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);//将int数据写入输出流
		dos.writeBoolean(true);//将boolean类型数据写入输出流
		dos.writeDouble(9887.543);将double类型数据写入输出流

		dos.close();
	}
}

四、ByteArrayInputStream和ByteArrayOutputStream
1、用于操作字节数组的流对象
ByteArrayInputStream :在构造的时候,需要接收数据源。而且数据源是一个字节数组。
ByteArrayOutputStream: 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。这就是数据目的地。
2、因为这两个流对象都操作的是数组,并没有使用系统资源。所以,不用进行close关闭。
3、 在流操作规律讲解时:
源设备
键盘 System.in,硬盘 FileStream,内存 ArrayStream。
目的设备:
控制台 System.out,硬盘FileStream,内存 ArrayStream

示例:
/*用流的读写思想来操作数组。*/
import java.io.*;
class ByteArrayStream 
{
	public static void main(String[] args) 
	{
		//数据源。
		ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFD".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());

	//	bos.writeTo(new FileOutputStream("a.txt"));

	}
}

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



你可能感兴趣的:(java学习笔记)