第15章.输入/输出
Posted lanshanxiao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第15章.输入/输出相关的知识,希望对你有一定的参考价值。
File类:
访问文件和目录:
File类可以使用文件路径字符串来创建File实例,该文件路径字符串既可以是绝对路径,也可以是相对路径。默认情况下,系统总是依据用户的工作路径来解释相对路径,这
个路径由系统属性“user.dir”指定,通常也就是运行Java虚拟机时所在的路径。
File类提供了很多方法来操作文件和目录:
访问文件名相关的方法:
1.String getName():返回此File对象所表示的文件名或路径名(若是路径,则返回最后一级子路径名)。
2.String getPath():返回次File对象所对应的路径名
3.File getAbsoluteFile():返回此File对象的绝对路径
4.String getAbsolutePath():返回此File对象所对应的绝对路径名。
5.String getParent():返回此File对象所对应目录(最后一级子目录)的父目录名
6.boolean renameTo(File newName):重命名此File对象所对应的文件或目录,若重命名成功,则返回true,否则返回false
文件检测相关的方法:
1.boolean exists():判断File对象所对应的文件或目录是否存在
2.boolean canWrite():判断File对象所对应的文件和目录是否可写
3.boolean canRead():判断File对象所对应的文件和目录是否可读
4.boolean isFile():判断File对象所对应的是否是文件,而不是目录
5.boolean isDirectory():判断File对象所对应的是否是目录,而不是文件
6.boolean isAbsolute():判断File对象所对应的文件或目录是否是绝对路径。该方法消除了不同平台的差异,可直接判断File对象是否为绝对路径。
获取常规文件信息:
1.long lastModified():返回文件的最后修改时间
2.long length():返回文件内容的长度
文件操作相关的方法:
1.boolean createNewFile():当此File对象所对应的文件不存在时,该方法将新建一个该File对象所指定的新文件,若创建成功返回true,否则返回false
2.boolean delete():删除File对象所对应的文件或路径
3.static File createTempFile(String prefix, String suffix):在默认的临时文件目录中创建一个临时的空文件,使用给定前缀、系统生成的随机数和给定后缀作为文件名。
File类可以直接调用该方法,prefix参数必须至少3字节长。建议前缀使用一个短的、有意义的字符串,如:hjb、mail。suffix参数可以为null,使用默认的后缀.tmp
4.static File createTempFIle(String prefix, String suffix, File directory):在directory所指定的目录中创建一个临时的空文件,使用给定前缀、系统生成的随机数和给定
后缀作为文件名。
5.void deleteOnExit():注册一个删除钩子,指定当Java虚拟机退出时,删除File对象所对应的文件和目录
目录操作相关的方法:
1.boolean mkdir():创建一个File对象所对应的目录,若创建成功,则返回true,否则返回false。调用该方法时File对象必须对应一个路径,而不是一个文件。
2.String[] list():列出File对象的所有子文件名和路径,返回String[]数组
3.File[] listFiles():列出File对象的所有子文件和路径,返回Flie数组
4.static File[] listRoots():列出系统所有的根路径
下面程序以几个简单的方法来测试以下File类的功能:
1 import java.io.*; 2 /** 3 * Description: 4 * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a> 5 * <br/>Copyright (C), 2001-2016, Yeeku.H.Lee 6 * <br/>This program is protected by copyright laws. 7 * <br/>Program Name: 8 * <br/>Date: 9 * @author Yeeku.H.Lee kongyeeku@163.com 10 * @version 1.0 11 */ 12 public class FileTest 13 { 14 public static void main(String[] args) 15 throws IOException 16 { 17 // 以当前路径来创建一个File对象 18 File file = new File("."); 19 // 直接获取文件名,输出一点 20 System.out.println(file.getName()); 21 // 获取相对路径的父路径可能出错,下面代码输出null 22 System.out.println(file.getParent()); 23 // 获取绝对路径 24 System.out.println(file.getAbsoluteFile()); 25 // 获取上一级路径 26 System.out.println(file.getAbsoluteFile().getParent()); 27 // 在当前路径下创建一个临时文件 28 File tmpFile = File.createTempFile("aaa", ".txt", file); 29 // 指定当JVM退出时删除该文件 30 tmpFile.deleteOnExit(); 31 // 以系统当前时间作为新文件名来创建新文件 32 File newFile = new File(System.currentTimeMillis() + ".txt"); 33 System.out.println("newFile对象是否存在:" + newFile.exists()); 34 // 以指定newFile对象来创建一个文件 35 newFile.createNewFile(); 36 // 以newFile对象来创建一个目录,因为newFile已经存在, 37 // 所以下面方法返回false,即无法创建该目录 38 newFile.mkdir(); 39 // 使用list()方法来列出当前路径下的所有文件和路径 40 String[] fileList = file.list(); 41 System.out.println("====当前路径下所有文件和路径如下===="); 42 for (String fileName : fileList) 43 { 44 System.out.println(fileName); 45 } 46 // listRoots()静态方法列出所有的磁盘根路径。 47 File[] roots = File.listRoots(); 48 System.out.println("====系统所有根路径如下===="); 49 for (File root : roots) 50 { 51 System.out.println(root); 52 } 53 } 54 }
// 以系统当前时间作为新文件名来创建新文件
File newFile = new File(System.currentTimeMillis() + ".txt");
System.out.println("newFile对象是否存在:" + newFile.exists());
上面程序中这两句不懂,为什么明明存在的一个文件,却返回一个false?
文件过滤器:
在File类的list方法中可以接受一个FilenameFilter参数,通过该参数可以只列出符合条件的文件。
FilenameFilter接口里包含了一个accept(File dir, String name)方法,该方法依次对指定File的所有子目录或文件进行迭代,若该方法返回true,则list()方法会列出该子目录
或文件:
1 import java.io.File; 2 3 public class FilenameFilterTest{ 4 public static void main(String[] args){ 5 File file = new File("."); 6 //使用Lambda表达式(目标类型为FilenameFiler)实现文件过滤器 7 //若文件名以.java结尾,或者文件对应一个路径,则返回true 8 String[] nameList = file.list((dir, name) -> name.endsWith(".java") || new File(name).isDirectory()); 9 for(String name : nameList){ 10 System.out.println(name); 11 } 12 } 13 }
字节流和字符流:
1 import java.io.FileInputStream; 2 import java.io.IOException; 3 4 public class FileInputStreamTest { 5 public static void main(String[] args) throws IOException{ 6 //创建字节输入流 7 FileInputStream fis = new FileInputStream("FileInputStreamTest.java"); 8 //创建一个长度为1024的“竹筒” 9 byte[] bbuf = new byte[1024]; 10 //用于保存实际读取的字节数 11 int hasRead = 0; 12 //使用循环来重复“取水”过程 13 while((hasRead = fis.read(bbuf)) > 0){ 14 //取出“竹筒”中的水滴(字节),将字节数组换成字符串输入 15 System.out.print(new String(bbuf, 0, hasRead)); 16 } 17 18 //关闭文件输入流,放在finally块里更安全 19 fis.close(); 20 } 21 }
程序最后关闭文件输入流,程序里打开的文件IO资源不属于内存里的资源,垃圾回收机制无法回收该资源,所以应该显示关闭文件IO资源。也可用try语句自动关闭IO流:
1 import java.io.FileReader; 2 import java.io.IOException; 3 4 public class FileReaderTest{ 5 public static void main(String[] args) throws IOException{ 6 try( 7 //创建字符输入流 8 FileReader fr = new FileReader("FileReaderTest.java"); 9 ){ 10 //创建一个长度为32的“竹筒” 11 char[] cbuf = new char[32]; 12 //用于保存实际读取的字符数 13 int hasRead = 0; 14 //使用循环来重复“取水”过程 15 while((hasRead = fr.read(cbuf)) > 0){ 16 //取出“竹筒”中的水滴(字符),将字符数组转换成字符串输入! 17 System.out.print(new String(cbuf, 0, hasRead)); 18 } 19 }catch(IOException ex){ 20 ex.printStackTrace(); 21 } 22 } 23 }
InputStream和Reader还支持如下几个方法来移动记录指针:
1.void mark(int readAheadLimit):在记录指针当前位置记录一个标记。
2.boolean markSupported():判断此输入流是否支持mark()操作,即是否支持记录标记
3.void reset():将此流的记录指针重新定位到上一次记录标记(mark)的位置
4.long skip(long n):记录指针向前移动n个字节/字符
OutputStream和Writer:
OutputStream和Writer类提供如下方法:
1.void write(int c):将指定的字节/字符输出到输出流中,其中c既可以代表字节,也可以代表字符
2.void write(byte[] / char[] buf):将字节数组/字符数组中的数据输出到指定输出流中
3.void write(byte[] / char[] buf, int off, int len):将字节数组/字符数组中从off位置开始,长度为len的字节/字符书粗到输出流中。
Writer还提供以下两个方法:
1.void write(String str):将str字符串里包含的字符串输出到指定输出流中
2.void write(String str, int off, int len):将str字符串里从off位置开始,长度为len的字符输出到指定输出流中
1 import java.io.FileInputStream; 2 import java.io.FileOutputStream; 3 import java.io.IOException; 4 5 public class FileOutputStreamTest{ 6 public static void main(String[] args){ 7 try( 8 //创建字节输入流 9 FileInputStream fis = new FileInputStream("FileOutputStreamTest.java"); 10 //创建字节输出流 11 FileOutputStream fos = new FileOutputStream("newFile.txt") 12 ){ 13 byte[] bbuf = new byte[32]; 14 int hasRead = 0; 15 //循环从输入流中取出数据 16 while((hasRead = fis.read(bbuf)) > 0){ 17 //每次读取一次,即写入文件输入流,读了多少,就写多少 18 fos.write(bbuf, 0, hasRead); 19 } 20 }catch(IOException ioe){ 21 ioe.printStackTrace(); 22 } 23 } 24 }
若希望直接输出字符串内容,则使用Writer会更好:
1 import java.io.FileWriter; 2 import java.io.IOException; 3 4 public class FileWriterTest{ 5 public static void main(String[] args){ 6 try( 7 FileWriter fw = new FileWriter("poem.txt") 8 ){ 9 fw.write("锦瑟 - 李商隐 \\r\\n"); 10 fw.write("锦瑟无端五十弦,一弦一柱思华年。 \\r\\n"); 11 fw.write("庄生晓梦迷蝴蝶,望帝春心托杜鹃。 \\r\\n"); 12 fw.write("沧海月明珠有泪,蓝田日暖玉生烟。 \\r\\n"); 13 fw.write("此情可待成追忆,只是当时已惘然。 \\r\\n"); 14 }catch(IOException ioe){ 15 ioe.printStackTrace(); 16 } 17 } 18 }
处理流的用法:
下面程序使用PrintStream处理刘来包装OutputStream,使用处理流后的输出流在输出时将更加方便:
1 import java.io.FileOutputStream; 2 import java.io.PrintStream; 3 import java.io.IOException; 4 5 public class PrintStreamTest{ 6 public static void main(String[] args){ 7 try( 8 FileOutputStream fos = new FileOutputStream("test.txt"); 9 PrintStream ps = new PrintStream(fos) 10 ){ 11 //使用PrintStream执行输出 12 ps.println("普通字符串"); 13 //直接使用PrintStreamTest输出对象 14 ps.println(new PrintStreamTest()); 15 }catch(IOException ioe){ 16 ioe.printStackTrace(); 17 } 18 } 19 }
1 import java.io.StringReader; 2 import java.io.IOException; 3 import java.io.StringWriter; 4 5 public class StringNodeTest 6 { 7 public static void main(String[] args) 8 { 9 String src = "从明天起,做一个幸福的人\\n" 10 + "喂马,劈柴,周游世界\\n" 11 + "从明天起,关心粮食和蔬菜\\n" 12 + "我有一所房子,面朝大海,春暖花开\\n" 13 + "从明天起,和每一个亲人通信\\n" 14 + "告诉他们我的幸福\\n"; 15 char[] buffer = new char[32]; 16 int hasRead = 0; 17 try( 18 StringReader sr = new StringReader(src)) 19 { 20 // 采用循环读取的访问读取字符串 21 while((hasRead = sr.read(buffer)) > 0) 22 { 23 System.out.print(new String(buffer ,0 , hasRead)); 24 } 25 } 26 catch (IOException ioe) 27 { 28 ioe.printStackTrace(); 29 } 30 try( 31 // 创建StringWriter时,实际上以一个StringBuffer作为输出节点 32 // 下面指定的20就是StringBuffer的初始长度 33 StringWriter sw = new StringWriter()) 34 { 35 // 调用StringWriter的方法执行输出 36 sw.write("有一个美丽的新世界,\\n"); 37 sw.write("她在远方等我,\\n"); 38 sw.write("哪里有天真的孩子,\\n"); 39 sw.write("还有姑娘的酒窝\\n"); 40 System.out.println("----下面是sw的字符串节点里的内容----"); 41 // 使用toString()方法返回StringWriter的字符串节点的内容 42 System.out.println(sw.toString()); 43 } 44 catch (IOException ex) 45 { 46 ex.printStackTrace(); 47 } 48 } 49 }
转换流:
两个转换流用于实现将字节流转换为字符流,其中InputStreamReader将字节输入流转换为字符输入流,OutputStreamWriter将字节输出流转换为字符输出流。
1 import java.io.InputStreamReader; 2 import java.io.BufferedReader; 3 import java.io.IOException; 4 5 public class KeyinTest 6 { 7 public static void main(String[] args) 8 { 9 try( 10 // 将Sytem.in对象转换成Reader对象 11 InputStreamReader reader = new InputStreamReader(System.in); 12 // 将普通Reader包装成BufferedReader 13 BufferedReader br = new BufferedReader(reader)) 14 { 15 String line = null; 16 // 采用循环方式来一行一行的读取 17 while ((line = br.readLine()) != null) 18 { 19 // 如果读取的字符串为"exit",程序退出 20 if (line.equals("exit")) 21 { 22 System.exit(1); 23 } 24 // 打印读取的内容 25 System.out.println("输入内容为:" + line); 26 } 27 } 28 catch (IOException ioe) 29 { 30 ioe.printStackTrace(); 31 } 32 } 33 }
由于BufferedReader具有一个readLine()方法,可以非常方便依次读入一行内容,所以经常把读取文本内容的输入流包装成BufferedReader,用来方便地读取输入流的文
本内容
推回输入流:
PushbackInputStream和PushbackReader提供了如下三个方法:
1.void unread(byte[] / char[] buf):将一个字节/字符数组内容推回到推回缓冲区里,从而允许重复读取刚刚读取的内容
2.void unread(byte[] / char[] b, int off, int len):将一个字节/字符数组里从off开始,长度为len字节/字符的内容推回到推回缓冲区里,从而重复读取刚刚读取的内容
3.void unread(int b):将一个字节/字符推回到推回缓冲区里,从而允许重复读取刚刚读取的内容。
1 import java.io.PushbackInputStream; 2 import java.io.PushbackReader; 3 import java.io.FileReader; 4 import java.io.IOException; 5 6 public class PushbackTest 7 { 8 public static void main(String[] args) 9 { 10 try( 11 // 创建一个PushbackReader对象,指定推回缓冲区的长度为64 12 PushbackReader pr = new PushbackReader(new FileReader( 13 "PushbackTest.java") , 64)) 14 { 15 char[] buf = new char[32]; 16 // 用以保存上次读取的字符串内容 17 String lastContent = ""; 18 int hasRead = 0; 19 // 循环读取文件内容 20 while ((hasRead = pr.read(buf)) > 0) 21 { 22 // 将读取的内容转换成字符串 23 String content = new String(buf , 0 , hasRead); 24 int targetIndex = 0; 25 // 将上次读取的字符串和本次读取的字符串拼起来, 26 // 查看是否包含目标字符串, 如果包含目标字符串 27 if ((targetIndex = (lastContent + content) 28 .indexOf("new PushbackReader")) > 0) 29 { 30 // 将本次内容和上次内容一起推回缓冲区 31 pr.unread((lastContent + content).toCharArray()); 32 // 重新定义一个长度为targetIndex的char数组 33 if(targetIndex > 32) 34 { 35 buf = new char[targetIndex]; 36 } 37 // 再次读取指定长度的内容(就是目标字符串之前的内容) 38 pr.read(buf , 0 , targetIndex); 39 // 打印读取的内容 40 System.out.print(new String(buf , 0 ,targetIndex)); 41 System.exit(0); 42 } 43 else 44 { 45 // 打印上次读取的内容 46 System.out.print(lastContent); 47 // 将本次内容设为上次读取的内容 48 lastContent = content; 49 } 50 } 51 } 52 catch (IOException ioe) 53 { 54 ioe.printStackTrace(); 55 } 56 } 57 }
第3章-15.删除重复字符 (20分)