一、概念:IO流用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
流按操作数据分为两种:字节流与字符流。
流按流向分为:输入流,输出流。
二、IO流常用基类
字节流的抽象基类:
• InputStream , OutputStream。
字符流的抽象基类:
• Reader , Writer。
注:由这四个类派生出来的子类名称都是
以其父类名作为子类名的后缀。
• 如: InputStream的子类FileInputStream。
• 如: Reader的子类FileReader
三、字符流——创建文件
创建流对象,建立数据存放文件
• FileWriter fw = new FileWriter(“Test.txt”);
调用流对象的写入方法,将数据写入流
• fw.write(“text”);
关闭流资源,并将流中的数据清空到文件中。
• fw.close();
1、写文件
例:package aaa;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
public static void main(String[] args) throws IOException {
//创建一个可以往文件中写入字符数据的字符输出流对象。
/*
* 既然是往一个文件中写入文字数据,那么在创建对象时,就必须明确该文件(用于存储数据的目的地)。
* 如果文件不存在,则会自动创建。
* 如果文件存在,则会被覆盖。
* 如果构造函数中加入true,可以实现对文件进行续写!
*/
FileWriter fWriter = new FileWriter("D:demo.txt",true);
/*
* 调用Writer对象中的write(string)方法,写入数据。
* 其实数据写入到临时存储缓冲区中。
*/
fWriter.write("adfsadfsafa");
fWriter.flush();//进行刷新,将数据直接写到目的地中。
fWriter.write("dtrdtrd");//关闭流,关闭资源。在关闭前会先调用flush刷新缓冲中的数据到目的地。
fWriter.close();
}
}
完整的写法:
private static final String LINE_SEPARATOR = System.getProperty("line.separator");//换行
public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("k:\\demo.txt");
fw.write("abcde" + LINE_SEPARATOR + "hahaha");
} catch (IOException e) {
System.out.println(e.toString());
} finally {
if (fw != null)
try {
fw.close();
} catch (IOException e) {
// code....
throw new RuntimeException("关闭失败");
}
}
}
四、字符流——读取文件
建立一个流对象,将已存在的一个文件加载进
流。
• FileReader fr = new FileReader(“Test.txt”);
创建一个临时存放数据的数组。
• char[] ch = new char[1024];
调用流对象的读取方法将流中的数据读入到数组
中。
• fr.read(ch);
2、读文件:需求:读取一个文本文件。将读取到的字符打印到控制台.
//第一种写法
package cn.itcast.p3.io.filereader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
//1,创建读取字符数据的流对象。
/*
* 在创建读取流对象时,必须要明确被读取的文件。一定要确定该文件是存在的。
* 用一个读取流关联一个已存在文件。
*/
FileReader fr = new FileReader("demo.txt");
int ch = 0;
while((ch=fr.read())!=-1){
System.out.println((char)ch);
这两种写法的区别:第一种一次只能读取一个字符,第二种写法一次能读取多个字符,减少循环。所以第二种写法更有优势。
}
fr.close();
}
}
//第二种写法:
package cn.itcast.p3.io.filereader;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo2 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("demo.txt");
/*
* 使用read(char[])读取文本文件数据。
* 先创建字符数组。
*/
char[] buf = new char[1024];
int len = 0;
while((len=fr.read(buf))!=-1){
System.out.println(new String(buf,0,len));
}
fr.close();
}
}
完整代码
public class FileWriterDemo {
public static void main(String[] args) throws IOException {
FileReader fr = null;
try {
fr = new FileReader("c:\\test.txt");
char[] buf = new char[1024];
int len = 0;
while ((len = fr.read(buf)) != -1) {
System.out.println(new String(buf, 0, len));
}
} catch (IOException e) {
System.out.println("read-Exception :" + e.toString());
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
System.out.println("close-Exception :" + e.toString());
}
}
}
}
}
注意:
定义文件路径时,可以用“/”或者“\\”。
在创建一个文件时,如果目录下有同名文
件将被覆盖。
在读取文件时,必须保证该文件已存在,
否则出异常。
练习:将D的文件复制到E盘
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
//练习:将D的文件复制到E盘
//第一种 一个一个的读
public class CopyText {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileReader fr = new FileReader("D:\\1.txt");
FileWriter fw = new FileWriter("e:\\2.txt");
int ch = 0;
while ((ch = fr.read()) != -1) {
fw.write(ch);
}
fr.close();
fw.close();
}
}
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
//第二种 一次读多个放到数组里面
//练习:将D的文件复制到E盘
public class CopyText {
private static final int BUFFER_SIZE = 1024;
public static void main(String[] args) throws IOException {
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("D:\\1.txt");
fw = new FileWriter("e:\\2.doc");
char[] buf=new char[BUFFER_SIZE];//缓冲区 创建一个临时容器,用于缓存读取到的字符
int len=0;
while((len=fr.read(buf))!=-1){fw.write(buf, 0, len);}
} catch (Exception e) {
throw new RuntimeException("读写失败");
} finally {
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
五、字符流的缓冲区
缓冲区的出现提高了对数据的读写效率
对应类: BufferWriter BufferReader
缓冲区要结合流才可以使用,是在流的就出上对流的功能进行了增强。
1、BufferReader举例:
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
public class CopyText {
public static void main(String[] args) throws IOException {
FileReader fr=new FileReader("D:\\1.txt");
BufferedReader bufr=new BufferedReader(fr);
String line=null;
while((line=bufr.readLine())!=null)
System.out.println(line);
bufr.close();
}
}
2、BufferedWriter写入举例:
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedWriterDemo {
private static final String LINE_SEPARATOR = System
.getProperty("line.separator");
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileWriter fw = new FileWriter("buf.txt");
//为了提高写入效率,使用字符流的缓冲区,创建了一个字符写入流的缓冲区对象,并额指定要缓冲的流对象相关联
BufferedWriter bufw = new BufferedWriter(fw);
for (int i = 0; i < 4; i++) {
bufw.write("asdfghjk" + i);
bufw.newLine();
bufw.flush();
}
bufw.close();
}
}
练习:利用BufferedReader和BufferedWriter复制文件
import java.io.*;
public class CopyTextByBufTest {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileReader fr = new FileReader("buf.txt");
BufferedReader bufr = new BufferedReader(fr);
FileWriter fw = new FileWriter("buf_Copy.txt");
BufferedWriter bufw = new BufferedWriter(fw);
String line = null;
while ((line = bufr.readLine()) != null) {
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufw.close();
bufr.close();
}
}
六、装饰者模式
对原有类进行了功能的改变,增强。
例:
public class PersonDemo {
public static void main(String[] args) {
Person p = new Person();
p.chiFan();
NewPerson p1 = new NewPerson(p);
p1.chiFan();
}
}
class Person {
void chiFan() {
System.out.println("吃饭");
}
}
// 这个类的出现是为了增强Person而出现的。
class NewPerson {
private Person p;
NewPerson(Person p) {
this.p = p;
}
public void chiFan() {
System.out.println("开胃酒");
p.chiFan();
System.out.println("甜点");
}
}
利用LineNumberReader装饰类设置行号。
import java.io.*;
public class LineNumberReaderDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileReader fr = new FileReader("buf.txt");
LineNumberReader lnr = new LineNumberReader(fr);
String line = null;
lnr.setLineNumber(100);
while ((line = lnr.readLine()) != null) {
System.out.println(lnr.getLineNumber() + ":" + line);
}
lnr.close();
}
}
七、字节流
基本操作与字符流相同,但是它不仅可以操作字符,还可以操作其他媒体文件
FileInputStream 读取流 ,FileOutputStream 输出流。
1、读取流举例:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
public class ByteStreamDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
demo_read();
}
static void demo_read() throws IOException {
FileInputStream fis = new FileInputStream("IO.txt");
System.out.println(fis.available());
//第一种读取方式
byte[] buf = new byte[fis.available()];
fis.read(buf);
System.out.println(new String(buf));
//第二种读取方式,建议使用这种
byte[] buf1=new byte[1024];
int len=0;
while((len=fis.read(buf1))!=-1)
{
System.out.print(new String(buf1,0,len));
}
//第三种,一个字节的读
/* int ch=0;
while((ch=fis.read())!=-1)
{
System.out.print((char)ch);
}*/
fis.close();
}
}
2、FileOutputStream 输出流举例
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
public class ByteStreamDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//demo_read();
demo_write();
}
public static void demo_write() throws IOException {
//1,创建字节输出流对象。用于操作文件.如果没有就创建新的文件
FileOutputStream fos = new FileOutputStream("bytedemo.txt");
//2,写数据。直接写入到了目的地中。
fos.write("abcdefg".getBytes());
fos.close();//关闭资源动作要完成。
}
}
八、字节流的缓冲区
同样是提高了字节流的读写效率。
BufferedInputStream和BufferedOutputStream
几种读取文件的效率举例:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyMp3Test {
public static void main(String[] args) throws IOException {
copy_4();
}
// 千万不要用,效率没有!
public static void copy_4() throws IOException {
FileInputStream fis = new FileInputStream("c:\\0.mp3");
FileOutputStream fos = new FileOutputStream("c:\\4.mp3");
int ch = 0;
while((ch =fis.read())!=-1){
fos.write(ch);
}
fos.close();
fis.close();
}
//不建议。
public static void copy_3() throws IOException {
FileInputStream fis = new FileInputStream("c:\\0.mp3");
FileOutputStream fos = new FileOutputStream("c:\\3.mp3");
byte[] buf = new byte[fis.available()];
fis.read(buf);
fos.write(buf);
fos.close();
fis.close();
}
public static void copy_2() throws IOException {
FileInputStream fis = new FileInputStream("c:\\0.mp3");
BufferedInputStream bufis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("c:\\2.mp3");
BufferedOutputStream bufos = new BufferedOutputStream(fos);
int ch = 0;
while((ch=bufis.read())!=-1){
bufos.write(ch);
}
bufos.close();
bufis.close();
}
public static void copy_1() throws IOException {
FileInputStream fis = new FileInputStream("c:\\0.mp3");
FileOutputStream fos = new FileOutputStream("c:\\1.mp3");
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.close();
fis.close();
}
}
九、转换流
InputStreamReader :字节到字符的桥梁。解码。
OutputStreamWriter:字符到字节的桥梁。编码。
转换流的由来:1、字符流与字节流之间的桥梁。2、方便了字符流与字节流之间的操作
转换流的应用:字节流中的数据都是字符时,转成字符流操作更高效。
例:获取键盘输入的字符
import java.io.IOException;
import java.io.InputStream;
public class ReadKey {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
StringBuilder sb = new StringBuilder();
InputStream in = System.in;
int ch = 0;
//read()方法是阻塞式方法
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 {
sb.append((char) ch);
}
}
}
}
例2:利用转换流实现读取键盘的操作,一次读取一行。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
public class TransStreamDemo {
public static void main(String[] args) throws IOException {
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();
}
}
}
例2的简化版:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class TransStreamDemo2 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
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();
}
}
}
例3:将输入的字符,存到文件里。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class TransStreamDemo2 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
BufferedReader bufr = new BufferedReader(new InputStreamReader(
System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("buf.txt")));
String line = null;
while ((line = bufr.readLine()) != null) {
if ("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufw.close();
}
}
例3:将文件中的字符读取到控制台
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class TransStreamDemo2 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("buf.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.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufw.close();
}
}
例4:将一个文件中的内容复制到另一个文件中
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class TransStreamDemo2 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("buf.txt")));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("buf_Copy.txt")));
String line = null;
while ((line = bufr.readLine()) != null) {
if ("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufw.close();
}
}
九、字符编码
字符流的出现为了方便操作字符。
更重要是的加入了编码转换。
通过子类转换流来完成。
• InputStreamReader
• OutputStreamWriter
在两个对象进行构造的时候可以加入字符
集。
常见的编码表:
1、ASCII:美国标准信息交换码。 用一个字节的7位可以表示。
2、ISO8859-1:拉丁码表,欧洲码表。用一个字节的8位表示。
3、GB2312:中国的中文编码表。
4、GBK:中国的中文编码表升级,融合了更多的中文文字符
号。
5、Unicode:国际标准码,融合了多种文字。 所有文字都用两个字节来表示,Java语言使用的就是unicode
7、UTF-8:最多用三个字节来表示一个字符。
转换流的编码应用:
1、可以将字符以指定编码格式存储。
2、可以对文本数据指定编码格式来解读。
3、指定编码表的动作由构造函数完成。
字符编码: 编码:字符串→字节数组 解码:字节数组→字符串
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
public class TransStreamDemo3 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
write_1();
writeText_2();
writeText_3();// UTF-8编码写入
readText_1();
readText_2();//用UTF-8编码读取GBK编码的文件
}
public static void readText_2() throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream(
"gbk_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();
}
public static void readText_1() throws IOException {
FileReader fr = new FileReader("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();
}
public static void writeText_3() throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("u8_1.txt"), "UTF-8");
osw.write("你好");
osw.close();
}
public static void writeText_2() throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
"gbk_3.txt"), "GBK");
// 等同于FileWriter fw=new FileWriter("gbk_3.txt"); 系统默认是 GBK
/*
* 这两句代码的功能是等同的。 FileWriter:其实就是转换流指定了本机默认码表的体现。而且这个转换流的子类对象,可以方便操作文本文件。
* 简单说:操作文件的字节流+本机默认的编码表。 这是按照默认码表来操作文件的便捷类。
*
* 如果操作文本文件需要明确具体的编码。FileWriter就不行了。必须用转换流。
*/
osw.write("你好");
osw.close();
}
public static void write_1() throws IOException {
FileWriter fw = new FileWriter("gbk_1.txt");
fw.write("你好");
fw.close();
}
}
十、File类
1、用来将文件或者文件夹封装成对象
2、方便对文件与文件夹的属性信息进行操作。
3、File对象可以作为参数传递给流的构造函数。
4、了解File类中的常用方法。
例:初始化File类的几种方式
import java.io.File;
public class FileDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
constructorDemo();
}
public static void constructorDemo()
{
File f1=new File("D:\\1.txt");
System.out.println(f1.exists());
File f2=new File("D:\\","1.txt");
System.out.println(f2.exists());
File f3=new File("D:\\");
File f4=new File(f3,"a.txt");
System.out.println(f4.exists());
File f5=new File("D:"+File.separator+"1.txt");
System.out.println(f5);
}
}
File类常用的方法举例:
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Date;
public class FileMethodDemo {
public static void main(String[] args) {
/*
* File对象的常见方法。
*
* 1,获取。 1.1 获取文件名称。 1.2 获取文件路径。 1.3 获取文件大小。 1.4 获取文件修改时间。
*
* 2,创建与删除。
*
* 3,判断。
*
* 4, 重命名
*/
getDemo();
// createAndDeleteDemo();
// isDemo();
// renameToDemo();
// listRootsDemo();
}
输出结果:
parent:null
name:C:\Users\WH\Workspaces\MyEclipse Professional 2014\Test\IO.txt
path:IO.txt
len:8543
time:1470094643508
str_time:2016年8月2日 上午07时37分23秒
private static void getDemo() {
// TODO Auto-generated method stub
File file = new File("IO.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);
System.out.println("parent:" + file.getParent());
System.out.println("name:" + absPath);
System.out.println("path:" + path);
System.out.println("len:" + len);
System.out.println("time:" + time);
System.out.println("str_time:" + str_time);
}
}
private static void createAndDeleteDemo() {
//创建单级文件夹
输出结果:
false
true
true
File dir = new File("D:\\abc");
boolean b = dir.mkdir();
System.out.println(b);
System.out.println(dir.delete());
//创建多级文件夹
File dir1=new File("D:\\sds\\ds\\adsa\\sa\\as\\a");
dir1.mkdirs();
System.out.println(dir1.delete());//虽然输出结果True,但只能删除最底层的文件夹
}
public static void isDemo() throws IOException{
File f = new File("aaa");
输出结果:
b=true
true
false
f.createNewFile();
boolean b = f.exists();
System.out.println("b="+b);
// 最好先判断是否存在。
System.out.println(f.isFile());
System.out.println(f.isDirectory());
输出结果:getFreeSpace:419413291008
getTotalSpace:429492695040
getUsableSpace:419413291008
C:\
D:\
E:\
H:\
}
public static void listRootsDemo() {
File file = new File("d:\\");
System.out.println("getFreeSpace:"+file.getFreeSpace());
System.out.println("getTotalSpace:"+file.getTotalSpace());
System.out.println("getUsableSpace:"+file.getUsableSpace());
File[] files = File.listRoots();
for(File file1 : files){
System.out.println(file1);
}
}
public static void renameToDemo() {
File f1 = new File("c:\\9.mp3");
File f2 = new File("d:\\aa.mp3");
boolean b = f1.renameTo(f2);//将f1的文件重命名为f2的文件名
System.out.println("b="+b);
}
FileFilter应用举例:
import java.io.File;
import java.io.FileFilter;
public class FilterByHidden implements FileFilter {
public boolean accept(File pathname) {
return !pathname.isHidden();
}
}
import java.io.File;
import java.io.FilenameFilter;
public class FilterByJava implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
System.out.println(dir+"---"+name);
return name.endsWith(".txt");
}
}
import java.io.File;
import java.io.FilenameFilter;
public class SuffixFilter implements FilenameFilter{
private String suffix ;
public SuffixFilter(String suffix) {
super();
this.suffix = suffix;
}
@Override
public boolean accept(File dir, String name) {
return name.endsWith(suffix);
}
}
import java.io.File;
public class FistListDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
listDemo();
listDemo_2();
listDemo_3();
listDemo_4();
}
/**
* 查找C下不是隐藏的文件
*/
public static void listDemo_3() {
File dir = new File("c:\\");
File[] files = dir.listFiles(new FilterByHidden());
for(File file : files){
System.out.println(file);
}
}
/**
* 查找D盘下所有的文件和文件夹
*/
public static void listDemo() {
/*
* 获取当前目录下的文件以及文件夹的名称,包含隐藏文件。 调用list方法的File对象中封装的必须是目录。
* 否则会发生NullPointerException 如果访问的系统级目录也会发生空指针异常。
* 如果目录存在但是没有内容,会返回一个数组,但是长度为0.
*/
File file = new File("D:\\");
String[] names = file.list();
System.out.println(names.length);
for (String name : names) {
System.out.println(name);
}
}
/**
* 筛选出后缀为.txt的文件
*/
public static void listDemo_2() {
File dir = new File("D:\\");
String[] names = dir.list(new SuffixFilter(".txt"));
for (String name : names) {
System.out.println(name);
}
}
/**
* FileFilter 过滤文件:先遍历,找符合条件的再放到数组中输出出来
*/
public static void listDemo_4() {
File dir = new File("D:\\");
String[] names = dir.list(new FilterByJava());
for (String name : names) {
System.out.println(name);
}
}
}
十一、递归:函数自己调用自己。
注意:递归时一定要明确结束条件。
应用场景: 当某一功能要重复使用时。
注意:
* 1,递归一定明确条件。否则容易栈溢出。
* 2,注意一下递归的次数。
例:读取文件夹下的所有文件
import java.io.File;
public class FileTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
File dir = new File("D:");
listAll(dir, 0);
}
public static void listAll(File dir, int level) {
System.out.println(getSpace(level) + dir.getName());
// 获取指定目录下当前的所有文件夹或者文件对象。
level++;
File[] files = dir.listFiles();
for (int x = 0; x < files.length; x++) {
if (files[x].isDirectory()) {
listAll(files[x], level);
} else
System.out.println(getSpace(level) + files[x].getName());
}
}
private static String getSpace(int level) {
StringBuilder sb = new StringBuilder();
sb.append("|--");
for (int x = 0; x < level; x++) {
sb.insert(0, "| ");
}
return sb.toString();
}
}
例:递归删除文件夹下所有的文件和文件夹
import java.io.File;
public class RemoveDirTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
File dir = new File("D:\\脚本复制\\ewwe");
dir.delete();
removeDir(dir);
}
public static void removeDir(File dir) {
File[] files = dir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
removeDir(file);
} else {
System.out.println(file + ":" + file.delete());
}
}
System.out.println(dir+":"+dir.delete());
}
}
例:递归举例,计算数的和
public class DiGuiDemo {
/**
* @param args
*/
public static void main(String[] args) {
/*
* 递归:
* 函数自身直接或者间接的调用到了自身。
* 一个功能在被重复使用,并每次使用时,参与运算的结果和上一次调用有关。
* 这时可以用递归来解决问题。
* 注意:
* 1,递归一定明确条件。否则容易栈溢出。
* 2,注意一下递归的次数。
*/
int sum = getSum(9000);
System.out.println(sum);
}
public static int getSum(int num){
int x = 9;
if(num==1)
return 1;
return num+getSum(num-1);
}
}
十二、Properties集合
特点:
1,该集合中的键和值都是字符串类型。
2,集合中的数据可以保存到流中,或者从流获取。
通常该集合用于操作以键值对形式存在的配置文件。
例:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Properties;
import java.util.Set;
/*
* Map
* |--Hashtable
* |--Properties:
* Properties集合:
* 特点:
* 1,该集合中的键和值都是字符串类型。
* 2,集合中的数据可以保存到流中,或者从流获取。
*
* 通常该集合用于操作以键值对形式存在的配置文件。
*/
public class PropertiesDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
PropertiesUpDateAndAdd();
methodDemo_2();
methodDemo_3();
methodDemo_4();
PropertiesReadAndUpdate();
}
/**
* 对已有的配置文件中的信息进行修改。 思路:读取这个文件。 并将这个文件中的键值数据存储到集合中。 在通过集合对数据进行修改。
* 在通过流将修改后的数据存储到文件中。
* @throws IOException
*/
public static void PropertiesReadAndUpdate() throws IOException {
File file = new File("info.txt");
if (!file.exists()) {
file.createNewFile();
}
FileReader fr = new FileReader(file);
// 创建集合存储配置信息
Properties prop = new Properties();
// 将流中信息存储到集合中。
prop.load(fr);
prop.setProperty("wangwu", "16");
FileWriter fw = new FileWriter(file);
prop.store(fw, "");
prop.list(System.out);
fw.close();
fr.close();
}
/**
* 读取保存到本地的Properties文件
* @throws IOException
*/
public static void methodDemo_4() throws IOException {
Properties prop = new Properties();
// 集合中的数据来自于一个文件。
// 注意;必须要保证该文件中的数据是键值对。需要使用到读取流。
FileInputStream fis = new FileInputStream("info.txt");
// load方法
prop.load(fis);
prop.list(System.out);
}
/**
* 集合中的字符串键值信息持久化存储到文件中
* @throws IOException
*/
public static void methodDemo_3() throws IOException {
Properties prop = new Properties();
// 存储元素。
prop.setProperty("zhangsan", "30");
prop.setProperty("lisi", "31");
prop.setProperty("wangwu", "36");
prop.setProperty("zhaoliu", "20");
// 想要将这些集合中的字符串键值信息持久化存储到文件中。需要关联输出流。
FileOutputStream fos = new FileOutputStream("info.txt");
prop.store(fos, "info");
fos.close();
}
/**
* 演示Properties集合和流对象相结合的功能。
*/
public static void methodDemo_2() {
Properties prop = System.getProperties();
prop.list(System.out);
}
/**
* Properties集合的修改和增加
*/
public static void PropertiesUpDateAndAdd() {
Properties prop = new Properties();
// 存储元素
prop.setProperty("张三", "30");
prop.setProperty("lisi", "31");
prop.setProperty("wangwu", "36");
prop.setProperty("zhaoliu", "20");
// 修改元素
prop.setProperty("wangwu", "26");
Set<String> names = prop.stringPropertyNames();
for (String name : names) {
String value = prop.getProperty(name);
System.out.println(name + ":" + value);
}
}
}
练习:定义功能,获取一个应用程序运行的次数,如果超过5次,给出使用次数已到请注册的提示。并不要在运行程序。
思路:
1,应该有计数器。
每次程序启动都需要计数一次,并且是在原有的次数上进行计数。
2,计数器就是一个变量。 突然冒出一想法,程序启动时候进行计数,计数器必须存在于内存并进行运算。
可是程序一结束,计数器消失了。那么再次启动该程序,计数器又重新被初始化了。
而我们需要多次启动同一个应用程序,使用的是同一个计数器。
这就需要计数器的生命周期变长,从内存存储到硬盘文件中。
3,如何使用这个计数器呢?
首先,程序启动时,应该先读取这个用于记录计数器信息的配置文件。
获取上一次计数器次数。 并进行试用次数的判断。
其次,对该次数进行自增,并自增后的次数重新存储到配置文件中。
4,文件中的信息该如何进行存储并体现。
直接存储次数值可以,但是不明确该数据的含义。 所以起名字就变得很重要。
这就有了名字和值的对应,所以可以使用键值对。
可是映射关系map集合搞定,又需要读取硬盘上的数据,所以map+io = Properties.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class PropertiesTest {
public static void main(String[] args) throws IOException {
getAppCount();
}
/**
* @throws IOException
*/
public static void getAppCount() throws IOException {
File conFile = new File("count.properties");
if (!conFile.exists()) {
conFile.createNewFile();
}
FileInputStream fis = new FileInputStream(conFile);
Properties prop = new Properties();
prop.load(fis);
String value = prop.getProperty("time");
int count = 0;
if (value != null) {
count = Integer.parseInt(value);
if (count >= 5) {
throw new RuntimeException("使用次数已到,请注册,给钱!");
}
}
count++;
//将改变后的次数重新存储到集合中
prop.setProperty("time", count+"");
FileOutputStream fos=new FileOutputStream(conFile);
prop.store(fos, "count");
fos.close();
fis.close();
}
}
练习: 获取指定目录下,指定扩展名的文件(包含子目录中的)
这些文件的绝对路径写入到一个文本文件中。简单说,就是建立一个指定扩展名的文件的列表。 思路:
1,必须进行深度遍历。
2,要在遍历的过程中进行过滤。将符合条件的内容都存储到容器中。
3,对容器中的内容进行遍历并将绝对路径写入到文件中。
package Test23;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
File dir = new File("C:\\Users\\WH\\Workspaces\\MyEclipse Professional 2014\\Test");
FilenameFilter filter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".java");
}
};
List<File> list = new ArrayList<File>();
getFiles(dir, filter, list);
File destFile = new File(dir, "javalist.txt");
write2File(list, destFile);
}
/**
* 对指定目录中的内容进行深度遍历,并按照指定过滤器,进行过滤, 将过滤后的内容存储到指定容器List中。
* @param dir
* @param filter
* @param list
*/
public static void getFiles(File dir, FilenameFilter filter, List<File> list) {
File[] files = dir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
// 递归啦!
getFiles(file, filter, list);
} else {
// 对遍历到的文件进行过滤器的过滤。将符合条件File对象,存储到List集合中。
if (filter.accept(dir, file.getName())) {
list.add(file);
}
}
}
}
public static void write2File(List<File> list, File destFile)
throws IOException {
BufferedWriter bufw = null;
try {
bufw = new BufferedWriter(new FileWriter(destFile));
for (File file : list) {
bufw.write(file.getAbsolutePath());
bufw.newLine();
bufw.flush();
}
}
finally {
if (bufw != null)
try {
bufw.close();
} catch (IOException e) {
throw new RuntimeException("关闭失败");
}
}
}
}
总结:流的操作规律:
之所以要弄清楚这个规律,是因为流对象太多,开发时不知道用哪个对象合适。
想要知道开发时用到哪些对象。只要通过四个明确即可。
1,明确源和目的(汇)
源:InputStream Reader
目的:OutputStream Writer
2,明确数据是否是纯文本数据。
源:是纯文本:Reader
否:InputStream
目的:是纯文本 Writer
否:OutputStream
到这里,就可以明确需求中具体要使用哪个体系。
3,明确具体的设备。
源设备:
硬盘:File
键盘:System.in
内存:数组
网络:Socket流
目的设备:
硬盘:File
控制台:System.out
内存:数组
网络:Socket流
4,是否需要其他额外功能。
1,是否需要高效(缓冲区);
是,就加上buffer.
2,转换。
需求1:复制一个文本文件。
1,明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2,是否是纯文本?
是!
源:Reader
目的:Writer
3,明确具体设备。
源:
硬盘:File
目的:
硬盘:File
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
4,需要额外功能吗?
需要,需要高效。
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
================================================
需求2:读取键盘录入信息,并写入到一个文件中。
1,明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2,是否是纯文本呢?
是,
源:Reader
目的:Writer
3,明确设备
源:
键盘。System.in
目的:
硬盘。File
InputStream in = System.in;
FileWriter fw = new FileWriter("b.txt");
这样做可以完成,但是麻烦。将读取的字节数据转成字符串。再由字符流操作。
4,需要额外功能吗?
需要。转换。 将字节流转成字符流。因为名确的源是Reader,这样操作文本数据做便捷。
所以要将已有的字节流转成字符流。使用字节-->字符 。InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
FileWriter fw = new FileWriter("b.txt");
还需要功能吗?
需要:想高效。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
===================================================
需求3:将一个文本文件数据显示在控制台上。
1,明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2,是否是纯文本呢?
是,
源:Reader
目的:Writer
3,明确具体设备
源:
硬盘:File
目的:
控制台:System.out
FileReader fr = new FileReader("a.txt");
OutputStream out = System.out;//PrintStream
4,需要额外功能吗?
需要,转换。
FileReader fr= new FileReader("a.txt");
OutputStreamWriter osw = new OutputStreamWriter(System.out);
需要,高效。
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
================================================================
需求4:读取键盘录入数据,显示在控制台上。
1,明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2,是否是纯文本呢?
是,
源:Reader
目的:Writer
3,明确设备。
源:
键盘:System.in
目的:
控制台:System.out
InputStream in = System.in;
OutputStream out = System.out;
4,明确额外功能?
需要转换,因为都是字节流,但是操作的却是文本数据。
所以使用字符流操作起来更为便捷。
InputStreamReader isr = new InputStreamReader(System.in);
OutputStreamWriter osw = new OutputStreamWriter(System.out);
为了将其高效。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
============================================================
5,将一个中文字符串数据按照指定的编码表写入到一个文本文件中.
1,目的。OutputStream,Writer
2,是纯文本,Writer。
3,设备:硬盘File
FileWriter fw = new FileWriter("a.txt");
fw.write("你好");
注意:既然需求中已经明确了指定编码表的动作。
那就不可以使用FileWriter,因为FileWriter内部是使用默认的本地码表。
只能使用其父类。OutputStreamWriter.
OutputStreamWriter接收一个字节输出流对象,既然是操作文件,那么该对象应该是FileOutputStream
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName);
需要高效吗?
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName));
什么时候使用转换流呢?
1,源或者目的对应的设备是字节流,但是操作的却是文本数据,可以使用转换作为桥梁。
提高对文本操作的便捷。
2,一旦操作文本涉及到具体的指定编码表时,必须使用转换流 。
十三、IO包中的其他类
打印流
• PrintWriter与PrintStream
• 可以直接操作输入流和文件。
PrintStream:
1,提供了打印方法可以对多种数据类型值进行打印。并保持数据的表示形式。
2,它不抛IOException.
构造函数,接收三种类型的值:
* 1,字符串路径。
* 2,File对象。
* 3,字节输出流。
例:
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
public class PrintStreamDemo {
public static void main(String[] args) throws IOException {
PrintStream out = new PrintStream("print.txt");
// int by = read();
// write(by);
// out.write(610);//只写最低8位,
// out.print(97);//将97先变成字符保持原样将数据打印到目的地。
out.close();
}
}
PrintWriter:字符打印流。
构造函数参数:
1,字符串路径。
2,File对象。
3,字节输出流。
4,字符输出流。
例:
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class PrintWriterDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new FileWriter("out.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();
}
}
序列流
• SequenceInputStream
• 对多个流进行合并。
例:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
public class SequenceInputStreamDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*
* 需求:将1.txt 2.txt 3.txt文件中的数据合并到一个文件中。
*/
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int x=1; x<=3; x++){
al.add(new FileInputStream(x+".txt"));
}
Enumeration<FileInputStream> en = Collections.enumeration(al);
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("1234.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.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class SplitFileDemo {
private static final int SIZE = 1024 * 1024;
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
File file = new File("D:\\重庆测试数据.zip");
splitFile(file);
}
private static void splitFile(File file) throws IOException {
FileInputStream fis = new FileInputStream(file);
byte[] buf = new byte[SIZE];
FileOutputStream fos = null;
int len = 0;
int count = 1;
/*
* 切割文件时,必须记录住被切割文件的名称,以及切割出来碎片文件的个数。 以方便于合并。
* 这个信息为了进行描述,使用键值对的方式。用到了properties对象
*
*/
Properties prop = new Properties();
File dirFile = new File("D:\\partFiles");
if (!dirFile.exists())
dirFile.mkdir();
while ((len=fis.read(buf))!=-1) {
fos=new FileOutputStream(new File(dirFile,(count++)+".part"));
fos.write(buf,0,len);
fos.close();
}
prop.setProperty("partCount", count+"");
prop.setProperty("fileName", file.getName());
fos=new FileOutputStream(new File(dirFile,count+".properties"));
prop.store(fos, "Save file Info");
fos.close();fis.close();
}
}
将切割的文件合并,合并信息从配置文件中获取:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Properties;
public class MergerFile {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
File dir = new File("D:\\partFiles");
mergeFile_2(dir);
}
public static void mergeFile_2(File dir) throws IOException {
// 获取指定目录下的配置文件对象。
File[] files = dir.listFiles(new SuffixFilter(".properties"));
if (files.length != 1)
throw new RuntimeException(dir + ",该目录下没有Properties扩展名的文件或者不唯一");
//记录文件对象。
File conFile=files[0];
//获取该文件中的信息
Properties properties=new Properties();
FileInputStream fis=new FileInputStream(conFile);
properties.load(fis);
String fileName=properties.getProperty("fileName");
int count=Integer.parseInt(properties.getProperty("partCount"));
//获取该目录下的所有碎片文件。
File[] partFiles=dir.listFiles(new SuffixFilter(".part"));
if (partFiles.length!=(count-1)){
throw new RuntimeException("碎片文件不符合要求,个数不对!应该"+count+"个");
}
ArrayList<FileInputStream> a1=new ArrayList<FileInputStream>();
for (int i = 0; i < partFiles.length; i++) {
a1.add(new FileInputStream(partFiles[i]));
}
Enumeration<FileInputStream> en=Collections.enumeration(a1);
SequenceInputStream sisStream=new SequenceInputStream(en);
FileOutputStream fos=new FileOutputStream(new File(dir,fileName));
byte[] buf=new byte[1024];
int len=0;
while((len=sisStream.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sisStream.close();
}
}
操作对象
• ObjectInputStream与ObjectOutputStream
• 被操作的对象需要实现Serializable (标记接口);