Java基础22--IO--文件过滤器

22-1,键盘录入

键盘录入使用的是System.in,这个语句获取的是一个InputStream流对象,在通过这个对象的read()方法就可以获取键盘录入信息。

这个read()方法是阻塞式方法,也就是说,当JVM读到这个语句的时候,就会开始等待用户输入,直到用户输入结束符,才继续执行剩下的程序。

示例:

需求:读取一个键盘录入的数据,并打印在控制台上。

public class Demo {
	public static void main(String[] args) {
		InputStream in = System.in;
		int ch = in.read();//阻塞式方法,直到用户在控制台输入信息并回车,才继续执行下面的程序。
		System.out.println(ch);
		int ch1 = in.read();
		System.out.println(ch1);
		int ch2 = in.read();
		System.out.println(ch2);
		//假如我们输入a,则打印97 13 10,因为回车是两个字符,所以打印三个结果
		/*
		in.close();//会把系统流关闭,关闭后将无法从控制台获取数据,一般不要关闭
		InputStream in2 = System.in;//需要重新获取流
		int ch3 = int2.read();
		*/
	}
}

 

22-2,读取键盘录入练习

需求:获取用户在键盘录入的数据,并将数据变成大写打印在控制台上。如果用户输入的是over,则结束键盘录入。

思路:

(1)因为键盘录入只会读取一个字节,要判断是否是over,需要将读到的字符拼成字符串。

(2)既然要拼接字符串,就需要一个容器,使用StringBuilder。

(3)在用户回车之前将录入的数据变成字符串判断即可。

public class Demo {
	public static void main(String[] args) {
		//1.创建容器
		StringBuilder sb = new StringBuilder();
		//2.获取键盘读入流
		InputStream in = System.in;
		//3.定义变量记录读取到的字节,并循环获取
		int ch = 0;
		while((ch = in.read()) != -1) {
			//在存储之前要判断是否是换行标记,因为换行标记是不需要存储的
			if(ch = ‘\r‘)
				continue;
			if(ch = ‘\n‘) {
				String temp = sb.toString();
				if("over".equals(temp))
					break;
				System.out.println(temp.toUpperCase());
				sb.delete(0,sb.length());
			} else {
				//将读到的字节存储到StringBuilder中
				sb.append((char)ch);
			}
		}
	}
}

 

22-3,转换流、字节流-->字符流、字符流-->字节流

1,上一节的方法中要读入一行数据,那么能否用类似于readLine()的方法呢?readLine()是BufferedReader中的方法,在字节流中无法使用。想要使用字符流的readLine()方法,需要将字节流转换为字符流。

2,InputStreamReader类是字节流通向字符流的桥梁,它使用指定的charset读取字节并将其解码为字符,它使用的字符集可以由名称指定或显示给定,或者可以接收平台默认字符集。

3,为了达到最高效率,可以考虑在BufferedReader内包装InputStreamReader,例如:

    BufferedReaderin = new BufferedReader(new InputStreamReader(System.in));

4,示例

public class Demo {
	public static void main(String[] args) {
		//字节流
		InputStream in = System.in;
		//将字节流转换成字符流的桥梁--InputStreamReader
		InputStreamReader isr = new InputStreamReader(in);
		//字符流,用Buffer提高效率
		BufferedReader br = new BufferedReader(isr);
		String line = null;
		while((line = br.readLine())!=null) {
			if("over".equals(line))
				break;
			System.out.println(line.toUpperCase());
		}
	}
}

5,中文字符为两个字节,用字节流读入的一个中文,只会读取一个字节,无法读取出中文,若用字节流转成字符流后再读取,则可以直接读取出中文,其实是因为InputStreamReader在读取完成后,在底层自动做了查编码表的操作,返回的是编码表上的字符,所以可以直接查出中文。

6,OutputStreamWriter类,是字符流通向字节流的桥梁,可以使用指定的charset将要写入流中的字符编码成字节。每次调用write方法都会导致在给定字符(或字符集)上调用编码转换器。在底层写入输出流之前,得到的这些字节将在缓冲区中累积。

这里提供一种高效包装的方法:

Writer out = new BufferedWriter(newOutputStreamWriter(System.in));

7,示例

public class Demo {
	public static void main(String[] args) {
		InputStream in = System.in;
		InputStreamReader isr = new InputStreamReader(in);
		BufferedReader bufr = new BufferedReader(isr);

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

		String line = null;
		while((line = bufr.readLine()) != null) {
			if("over".equals(line))
				break;
			bufw.write(line.toUpperCase());
			bufw.newLine();//换行
			bufw.flush();//从缓冲中刷新出去
		}
	}
}

8,转换流图解

Java基础22--IO--文件过滤器

9,高效装饰的简化版写法,尽量记住

public class Demo {
	public static void main(String[] args) {
		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;
			bufw.write(line.toUpperCase());
			bufw.newLine();
			bufw.flush();
		}
	}
}

 

22-4,需求演示

1,需求一:将键盘录入的数据转成大写写入到一个文件中(当前目录的a.txt)。

public class Demo {
	public static void main(String[] args) {
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		//OutputStreamWriter需要接收一个字节流,且操作文件
		//就想到了FileOutputStream,并将控制台录入的数据写入到a.txt中
		BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt")));
		String line = null;
		while((line = bufr.readLine()) != null) {
			if("over".equals(line))
				break;
			bufw.write(line.toUpperCase());
			bufw.newLine();
			bufw.flush();
		}
	}
}

2,需求二:将一个文本文件的内容显示在控制台上。

这里读入为一个文件,输出为控制台。

public class Demo {
	public static void main(String[] args) {
		//读入为一个文件,且需要字节流,使用FileInputStream,
		BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("a.txt")));
		BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
		String line = null;
		while((line = bufr.readLine()) != null) {
			if("over".equals(line))
				break;
			bufw.write(line);
			bufw.newLine();
			bufw.flush();
		}
	}
}

需求三:将一个文本文件中的内容复制到另一个文本文件中。

同上面的思路,改为:

public class Demo {
	public static void main(String[] args) {
		BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("a.txt")));
		BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt")));
		String line = null;
		while((line = bufr.readLine()) != null) {
			if("over".equals(line))
				break;
			bufw.write(line);
			bufw.newLine();
			bufw.flush();
		}
	}
}

 

22-5,流操作的基本规律

转换流:

    InputStreamReader:字节到字符的桥梁,解码。

    OuptutStreamWriter:字符到字节的桥梁,编码。

流的操作规律:

之所以要弄清楚这个规律,是因为流对象太多,开始时不知道用哪个对象合适。

想要知道开发时用哪个对象,只要通过四个明确即可知道。

四个明确:

(1)明确源和目的地(汇)

    源:InputStream   Reader

    目的:OutputStream   Writer

(2)明确数据是否是纯文本数据

    源:是纯文本:Reader

       不是纯文本:InputStream

    目的:是纯文本:Writer

       不是纯文本:OutputStream

    到这里,就可以明确需求中具体要使用那个体系。

(3)明确具体设备

    源设备:

       硬盘:File

       键盘:System.in

       内存:数组

       网络:Socket流

    目的设备:

       硬盘:File

       键盘(控制台):System.out

       内存:数组

       网络:Socket流

    到这里已经基本OK。

(4)是否需要其他额外功能?

    1是否需要高效(缓冲区)?

       是:则加上Buffer

    2是否需要转换

       是:则加上转换流

    还有很多其他功能,如果需要,包装上即可。

 

22-6,四个明确练习-需求体现

1,需求1:赋值一个文本文件,用四个明确确定用那个对象。

(1)明确源和目的

    源:InputStream   Reader

    目的:OutputStream   Writer

(2)是否是纯文本?

    是!

       确定:源:Reader

              目的:Writer

(3)明确具体设备

    源:硬盘:File-->FileReader,FileInputStream

    目的:硬盘:File-->FileWriter,FileOutputStream

    使用:FileReader fr = newFileReader("a.txt")

           FileWrtierfw = new FileWriter("b.txt")

(4)需要额外功能么?

    需要高效!

    BufferedReaderbufr = new BufferedReader(new FileReader("a.txt"));

    BufferedWriterbufw = new BufferedWriter(new FileWriter("b.txt"));

2,需求2:读取键盘录入的信息,并写入到一个文件中。

(1)明确源和目的:

    源:InputStream   Reader

    目的:OutputStream   Writer

(2)是否是纯文本:

    是!

       确定:源:Reader

              目的:Writer

(3)明确设备

    源:键盘:System.in

    目的:硬盘:File

    InputStreamin = System.in;

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

    这样做可以完成,但是麻烦,将读取的字节数据转成字符串,再由字符流操作。

(4)需要额外功能么?

    需要:转换:将字节流转换成字符流,因为明确的源是Reader,这样操作文本数据更加便捷,所以要将已有的字节流转换成字符流,使用字节-->字符。InputStreamReader,此外,还需要高效处理,需要添加Buffer。

    BufferedReaderbufr = new BufferedReader(new InputStreamReader(System.in));

    BufferedWriterbufw = new BufferedWriter(new FileWriter("b.txt"));

 

22-7,需求体现2

1,需求3:将一个文本文件数据显示在控制台上。

前两个明确不变。

(3)明确具体设备

    源:硬盘:File

    目的:控制台:System.out

    FileReaderfr = new FileReader("a.txt");

    OutputStreamout = System.out;

(4)额外功能?

    需要转换流,将获取的字符流转换成字节流,操作更加方便。

    FileReaderfr = new FileReader("a.txt");

    OutputStreamWriterosw = new OutputStreamWriter(System.out);

    需要高效:

    BufferedReaderbufr = new BufferedReader(new FileReader("a.txt"));

    BufferedWriterbufw = new BufferedReader(new OutputStreamWriter(System.out));

 

需求4:读取键盘录入的数据,显示在控制台上。

前两步相同。

(3)明确设备:

    源:键盘:System.in

    目的:控制台:System.out

    InputStreamin = System.in;

    OutputStreamout = System.out;

(4)明确额外功能?

    转换:因为都是字节流,但是操作的却是文本数据,所以使用字符流更为便捷。

    InputStreamReaderisr = new InputStreamReader(System.in);

    OutputStreamWriterosw = new OutputStreamWriter(System.out);

    高效:

    BufferedReaderbufr = new BufferedReader(new InputStreamReader(System.in));

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

 

22-8,转换流的编码解码

1,用OutputStreamWriter或InputStreamReader的charset方法。

2,将一个中文字符串数据按照指定的编码表写入到一个文本文件中。

两种写出方式的比较:

(1)

    FileWriterfw = new FileWriter("gbk_1.txt");

    fw.write("你好");

    fw.close();

(2)在写文件时指定编码表,用转换流指定。

    OutputStreamWriterosw = new OutputStreamWriter(new FileOutputStream("gbk_3.txt","GBK"));

    osw.write("你好");

    osw.close();

这两个写法功能上是相同的。不同之处在于:

FileWriter:其实就是转换流指定了本机默认编码表的体现,而且这个转换流的子对象,可以方便操作文本文件,简单说:是操作文件的字节流+本机默认的编码表。这是按照默认编码表来操作文件的便捷类。

如果操作文件需要明确具体的编码,FileWriter就不行了,必须使用转换流。

3,用UTF-8写出"你好"

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

osw.write("你好");

osw.close();

用UTF-8写一个中文字符占三个字节,GBK占两个字节。

4,用FileReader读取gbk_1.txt

FileReader fr = newFileReader("gbk_1.txt");

char[] buf = new char[10];

int len = fr.read(buf);

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

System.out.println(str);

fr.close();

gbk_1.txt是用GBK编码的,本例也用系统默认的GBK解码,故可以显示"你好"。

如果本例读u8_1.txt则会识别出不期望的文字,u8_1.txt用UTF-8编码成六个字节,先拿到前两个去GBK中查找,查出一个字符,再用中间两个查,再用后两个查,所以会出现三个字符。

5,只能用转换流读取UTF-8的文件:

InputStreamReader isr = newInputStreamReader(new FileInputStream("u8_1.txt"),"UTF-8");

char[] buf = new char[10];

int len = isr.read(buf);

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

System.out.println(str);

isr.close();

6,需求:将一个中文字符串数据按照指定的编码写入到一个文本文件中。

(1)目的:OutputStream   Writer

(2)是纯文本:Writer

(3)设备:硬盘:File

    FileWriterfw = new FileWriter("a.txt");

    fw.write("你好");

注意:既然要求中已经明确了指定编码的操作,那就不可以使用FileWriter,因为FileWriter内部使用的是默认的编码表。只能使用其父类:OutputStreamWriter。OutputStreamWriter接收一个字符输出流对象,既然是操作文件,那么该对象应该是FileOutputStream。

    OuptutStreamWriterosw = new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName),

需要高效:

BufferedWriter bufw = newBufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName));

 

什么时候使用转换流呢?

(1)源或目的对应的设备是字节流,但操作的却是文本数据,可用转换器作为桥梁,提高对文本操作的便捷。

(2)一旦操作的文本涉及到具体的指定编码时,必须用转换流。

 

22-9,File对象-构造函数&字段

1,File类。

用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作,File对象可以作为参数传递给流的构造函数,要了解File类中的常用方法。

2,构造器:

File(File parent,String child)

File(String pathname)

File(String parent,String child)

File(URI uri)

示例:

public class Demo {
	public static void main(String[] args) {
		//可将一个已存在的,或者不存在的文件或者目录封装成file对象
		File f1 = new File("c:\\a.txt");
		File f2 = new File("c:\\","a.txt");
		File f = new File("c:\\");
		File f3 = new File(f,"a.txt");
		//用File.separator可以获取系统的名称分隔符
		File f4 = new File("c:"+File.separator+"abc"+File.separator+"a.txt");//c:\\abc\a.txt
	}
}

3,字段:

static String pathSeparator:与系统有关的路径分隔符,是个字符,比如环境变量中的path中的”;”,Unix中为”:”。

static String separator:名称分隔符,如文件路径中的”\”

static char pathSeparator:返回字符型

static char separator:返回字符型

 

22-10,File-常见功能-获取

public class Demo {
	public static void main(String[] args) {
		File file = new File("a.txt");
		String name = file.getName();//获取文件名称
		String absPath = file.getAbsolutePath();//绝对路径
		String path = file.getPath();
		long len = file.length();//获取大小
		long time = file.lastModified();//最后修改时间
		Date date = new Date(time);
		DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG);
		String str_time = dateFormat.format(date);//格式化时间
	}
}

 

22-11,File-创建&删除

文件的创建和删除演示:

public class Demo {
	public static void main(String[] args) {
		File file = new File("file.txt");
		//和输出流不一样,如果文件不存在,则创建,如果文件存在,则不创建。
		boolean b = file.createFile();//创建
		System.out.println(b);
		boolean b1 = file.delete();//删除
		//创建单级目录(文件夹)
		File dir = new File("abc");
		boolean b2 = dir.mkdir();//创建单级目录
		//删除这个目录,如果这个目录内有别的文件或文件夹,则无法删除,
		//文件正在被操作时,也无法删除。
		boolean b3 = dir.delete();
		//创建多级目录(多层文件夹)
		File dirs = new File("abc\\a\\b\\c\\d\\e\\f\\g");
		boolean b = dirs.mkdirs();//dirs对象此时封装的是最后一个文件夹g,
		dirs.delete();//删除的是文件夹g,windows的删除是从里向外删除的
	}
}

 

22-12,判断

判断指定的File是否存在,使用File的exists()方法。一般我们在创建一个文件的时候都会先判断一下这个文件是否存在,如果存在再创建,则会覆盖之前的,可能造成之前的数据丢失,为了数据安全,一般先判断一下。

public class Demo {
	public static void main(String[] args) {
		File f = new File("a.txt");
		if(!f.exists()) {
			//如果这个文件不存在,则创建
			f.createNewFile();
		}
		boolean isFile = f.isFile();//判断指定File是不是一个文件
		boolean isDirectory = f.isDirectory();//判断指定File是不是一个路径
	}
}

 

22-13,重命名

1,重命名

File f1 = new File("c:\\0.mp3");
File f2 = new File("c:\\9.mp3");
boolean b = f1.renameTo(f2);

以上操作会将c盘的0.mp3重命名为9.mp3。

2,如果是如下操作:

File f1 = new File("c:\\9.mp3");
File f2 = new File("d:\\aa.mp3");
boolean b = f1.renameTo(f2);

这个操作会将c盘的9.mp3剪切并重命名为aa.mp3。

 

22-14,系统根目录和容量获取

1,static File[] listRoots()

这时File中的一个静态方法,使用这个方法可以获取系统根路径的File对象数组。

其实获取的就是我们的c盘,d盘等。

2,获取容量

在获取了所有盘符以后,遍历File[]数组取出每一个盘,对每一个磁盘对象,可以获取其相关信息,例如:

public class Demo {
	public static void main(String[] args) {
		File[] files = File.listRoots();
		for(File file : files) {
			System.out.println(file.getFreeSpace());//可用空间
			System.out.println(file.getTotalSpace());//总空间
			System.out.println(file.getUsableSpace());//可用空间
		}
	}
}

 

22-15,获取目录内容

String[] list();如果File代表一个文件夹,则这个方法会列出这个文件夹下的文件以及文件夹的名称,包括隐藏文件,例如:

public class Demo {
	public static void main(String[] args) {
		File file = new File("c:\\");
		String[] names = file.list();
		System.out.println(names.length);//目录中文件的个数没有则返回0
		for(String name : names) {
			System.out.println(name);
		}
	}
}

调用list方法的File对象中封装的必须是目录,否则会发生NullPointerException异常。如果访问的是系统级目录也会发生空指针异常。

 

22-16,文件过滤器

过滤器可以根据文件的一些属性信息来筛选文件,过滤掉我们不需要的文件。例如,我们可以根据扩展名获取文件的集合。

需求:取出c盘下所有后缀为.java的文件。

思路:File中的list方法只能打印指定目录下的全部文件名,要想按照指定条件读取需要的文件,就需要用到过滤器Filter。

File中有一个String[] list(FilenameFilter filter)方法,这个方法接收一个过滤器,可以根据这个过滤器筛选文件列表的名称。

public class Demo {
	public static void main(String[] args) {
		listDemo();
	}
	public static void listDemo() {
		File dir = new File("c:\\");
		//使用自定义的后缀过滤器
		String[] names = dir.list(new SuffixFilter(".java"));
		for(String name : names) {
			System.out.println(name);
		}
	}
}
//实现过滤器类,需要实现FilenameFilter文件名称过滤器接口
import java.io.File;
import java.io.FilenameFilter;
public class SuffixFilter implements FilenameFilter {
	private String suffix;
	public SufferFilter(String suffix) {
		super();
		this.suffix = suffix;
	}
	//在这个接口中要实现accpet方法
	public boolean accept(File dir,String name) {
		//如果满足下面这个条件,则是符合条件的文件。
		//例如,要找出包含demo的文件名,return name.contains("demo")即可
		return name.endswith(suffix);
	}
}

2,过滤器Filter的实现过程

Java基础22--IO--文件过滤器

(1)指定盘符c:\\,并取得所有文件名,传入过滤器中。

(2)过滤器先调用list方法取出所有文件,封装到一个数组中,并遍历这个数组,取出符合accept中过滤条件的文件名,输出。

3,过滤器类必须实现一个过滤器接口,并实现accept方法。

4,取出所有非隐藏文件的文件名。

本例不是过滤文件名,不能用list方法取出名称了,这里还有一个更牛的方法listFiles(FileFilter filter),它返符合条件的文件对象的File[]数组,这里用到FileFilter文件过滤器。

实现:

public class Demo {
	public static void main(String[] args) {
		listDemo();
	}
	public static void listDemo() {
		File dir = new File("c:\\");
		File[] files = dir.listFiles(new FilterByHidden());
		for(File file : files) {
			System.out.println(file);
		}
	}
}
//编写文件过滤器类
public class FilterByHidden implements FileFilter {
	public boolean accept(File pathname) {
		return !pathname.isHidden();
	}
}


Java基础22--IO--文件过滤器

上一篇:机房收费系统——可行性研究报告


下一篇:unity3d笔记(4)——声音,视频播放控制