流的概念与文件类
在 Java 语言中,将与不同输入输出设备之间的数据传输抽象为流,程序允许通过流的方式与输入输出设备进行数据传输。
文件类即File类,通过查找相关的API手册即可获得相关的类、方法以及属性的使用,这是十分关键的一环,以后很多不知名的类,我们只需要大概有个印象就行,到时候通过实际使用过程中查找相对应的手册即可,当然熟悉相关类的基本方法的使用也是十分关键的。
文件类的常用方法
package com.test;
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
public class Test
{
public static void main(String[] args)
{
Scanner scanner=new Scanner(System.in);
System.out.println("请输入文件名,例如:d:\\1.png");
String s=scanner.nextLine();
//这里只是创建了一个指定路径与文件名的文件对象,并不是真实创建了一个文件,暂且称为映射文件。
File file=new File(s);
System.out.println("文件名:"+file.getName());
System.out.println("文件大小为:"+file.length()+"字节");
System.out.println("文件所在路径为:"+file.getAbsolutePath());
if (file.isHidden())
{
System.out.println("该文件是一个隐藏文件");
}
else
{
System.out.println("该文件不是一个隐藏文件");
}
//如果文件不存在(真实文件),就创建真实文件
if (!file.exists())
{
System.out.println("该文件不存在");
try
{
//这里才是创建了真实文件
file.createNewFile();
System.out.println("新文件创建成功");
}
catch(IOException e){}
}
}
}
输出:
请输入文件名,例如:d:\1.png
d:\hello.txt
文件名:hello.txt
文件大小为:0字节
文件所在路径为:d:\hello.txt
该文件不是一个隐藏文件
该文件不存在
新文件创建成功
遍历目录文件
package com.test;
import java.util.Scanner;
import java.io.File;
import java.io.FilenameFilter;
public class Test
{
public static void main(String args[])
{
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要访问的目录:");
String s = scanner.nextLine();//读取待访问的目录名
File dirFile = new File(s);//创建目录文件对象
String[] allresults = dirFile.list();//获取目录下的所有文件名
for (String name : allresults)
System.out.println(name);//输出所有文件名
System.out.println("输入文件扩展名:");
s = scanner.nextLine();
Filter_Name fileAccept = new Filter_Name();//创建文件名过滤对象
fileAccept.setExtendName(s);//设置过滤条件
String result[] = dirFile.list(fileAccept);//获取满足条件的文件名
for (String name : result)
System.out.println(name);//输出满足条件的文件名
}
}
class Filter_Name implements FilenameFilter
{
String extendName;
public void setExtendName(String s)
{
extendName = s;
}
public boolean accept(File dir, String name)
{//重写接口中的方法,设置过滤内容
return name.endsWith(extendName);
}
}
输出:
请输入要访问的目录:
d:
$RECYCLE.BIN
.temp
360Downloads
360Safe
360安全浏览器下载
360驱动大师目录
BaiduNetdiskDownload
Download
hello.txt
QQMusicCache
Software
System Volume Information
wjt
zhandawei
输入文件扩展名:
txt
hello.txt
删除文件和目录
public class DeleteDirectory {
/**
* 删除空目录
* @param dir 将要删除的目录路径
*/
private static void doDeleteEmptyDir(String dir) {
boolean success = (new File(dir)).delete();
if (success) {
System.out.println("Successfully deleted empty directory: " + dir);
} else {
System.out.println("Failed to delete empty directory: " + dir);
}
}
/**
* 递归删除目录下的所有文件及子目录下所有文件
* @param dir 将要删除的文件目录
* @return boolean Returns "true" if all deletions were successful.
* If a deletion fails, the method stops attempting to
* delete and returns "false".
*/
private static boolean deleteDir(File dir) {
if (dir.isDirectory()) {
String[] children = dir.list();
//递归删除目录中的子目录下
for (int i=0; i<children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
// 目录此时为空,可以删除
return dir.delete();
}
/**
*测试
*/
public static void main(String[] args) {
doDeleteEmptyDir("new_dir1");
String newDir2 = "new_dir2";
boolean success = deleteDir(new File(newDir2));
if (success) {
System.out.println("Successfully deleted populated directory: " + newDir2);
} else {
System.out.println("Failed to delete populated directory: " + newDir2);
}
}
}
字节流与字符流
字节流
字节输入流的作用是从数据输入源( 例如磁盘、 网络等)获取字节数据到应用程序( 内存)中。 InputStream是一个定义了 Java 流式字节输入模式的抽象类, 该类的所有方法在出错时都会引发一个 IOException 异常。
package com.test;
import java.util.Scanner;
import java.io.IOException;
import java.io.FileInputStream;
public class Test {
public static void main(String[] args)
{
byte[] b=new byte[1024];//设置字节缓冲区
int n=-1;
System.out.println("请输入要读取的文件名:(例如:d:\\hello.txt)");
Scanner scanner =new Scanner(System.in);
String str=scanner.nextLine();//获取要读取的文件名
try
{
FileInputStream in=new FileInputStream(str);//创建字节输入流
//遇到文尾时返回-1
while((n=in.read(b,0,1024))!=-1)
{//读取文件内容到缓冲区,并显示
String s=new String (b,0,n);
System.out.println(s);
}
//其实也是关闭输入流
in.close();//读取文件结束,关闭文件
}
catch(IOException e)
{
System.out.println("文件读取失败");
}
}
}
输出:
请输入要读取的文件名:(例如:d:\hello.txt)
d:\hello.txt
Hello Java
OutputStream 是定义了流式字节输出模式的抽象类, 该类的所有方法都返回一个 void 值并且在出错的情况下引发一个IOException 异常。
package com.test;
import java.util.Scanner;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.File;
public class Test {
public static void main(String[] args)
{
String content;//待输出字符串
byte[] b;//输出字节流
FileOutputStream out;//文件输出流
Scanner scanner = new Scanner(System.in);
System.out.println("请输入文件名:(例如,d:\\hello.txt)");
String filename=scanner.nextLine();
File file = new File(filename);//创建文件对象
if (!file.exists())
{//判断文件是否存在
System.out.println("文件不存在,是否创建?(y/n)");
String f =scanner.nextLine();
if (f.equalsIgnoreCase("n"))
System.exit(0);//不创建,退出
else
{
try
{
file.createNewFile();//创建新文件
}
catch(IOException e)
{
System.out.println("创建失败");
System.exit(0);
}
}
}
try
{//向文件中写内容
content="Hello";
//因为是字节流,所以需要将输入的转变成字节的形式
b=content.getBytes();
out = new FileOutputStream(file);//建立文件输出流
out.write(b);//完成写操作
out.close();//关闭输出流
System.out.println("文件写操作成功!");
}
catch(IOException e)
{e.getMessage();}
try
{//向文件中追加内容
System.out.println("请输入追加的内容:");
content = scanner.nextLine();
b=content.getBytes();
//第二个参数为true表示文件以设置搜索路径模式打开
out = new FileOutputStream(file,true);//创建可追加内容的输出流
out.write(b);//完成追加写操作
out.close();//关闭输出流
System.out.println("文件追加写操作成功!");
scanner.close();
}
catch(IOException e)
{e.getMessage();}
}
}
输出:
请输入文件名:(例如,d:\hello.txt)
d:\hello.txt
文件写操作成功!
请输入追加的内容:
你好
文件追加写操作成功!
字符流
尽管字节流提供了处理任何类型输入输出操作的足够的功能,但他们不能直接操作Unicode字符。字符流层次结构的顶层是Reader和Writer抽象类。
Reader 是专门用于输入数据的字符操作流, 它是一个抽象类,该类的所有方法在出错的情况下都将引发 IOException 异常。
Writer 是定义流式字符输出的抽象类, 所有该类的方法都返回一个 void 值并在出错的条件下引发IOException 异常。
package com.test;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.FileReader;
public class Test
{
public static void main(String args[ ]) throws IOException
{
String strLine;
String strTest="Welcome to the Java World!";
BufferedWriter bwFile=new BufferedWriter(new FileWriter("demo.txt"));
bwFile.write(strTest,0,strTest.length());
//清空缓冲区
bwFile.flush( );
System.out.println("成功写入demo.txt!");
BufferedReader bwReader=new BufferedReader(new FileReader("demo.txt"));
strLine=bwReader.readLine( );
System.out.println("从demo.txt读取的内容为:");
System.out.println(strLine);
}
}
输出:
成功写入demo.txt!
从demo.txt读取的内容为:
Welcome to the Java World!
文件流和字符缓冲流
文件流
FileReader 类创建了一个可以读取文件内容的 Reader 类。这两个构造方法都能引发一个 FileNotFoundException 异常。
FileWriter 创建一个可以写文件的 Writer 类。它们可以引发 IOException 或 SecurityException 异常。如果试图打开一个只读文件, 将引发一个 IOException 异常。
package com.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;
import java.io.InputStream;
import java.io.OutputStream;
public class Test
{
public static void main(String[] args) throws IOException
{
Scanner scanner=new Scanner(System.in);
System.out.println("请输入源文件名和目的文件名,中间用空格分隔");
String s=scanner.next();//读取源文件名
String d=scanner.next();//读取目的文件名
File file1=new File(s);//创建源文件对象
File file2=new File(d);//创建目的文件对象
if(!file1.exists())
{
System.out.println("被复制的文件不存在");
System.exit(1);
}
InputStream input=new FileInputStream(file1);//创建源文件流
OutputStream output=new FileOutputStream(file2);//创建目的文件流
if((input!=null)&&(output!=null))
{
int temp=0;
while((temp=input.read())!=(-1))
output.write(temp);//完成数据复制
}
input.close();//关闭源文件流
output.close();//关闭目的文件流
System.out.println("文件复制成功!");
}
}
字符缓冲流
缓冲流分为缓冲输入流和缓冲输出流,使用缓冲流可以减少应用程序与I/O设备之间的访问次数,提高运输效率;可以对缓冲区中的数据进行按需访问和预处理,增强访问的灵活性。
字节缓冲输入流 BufferedInputStream 类和字符缓冲输入流 BufferedReader 类。
缓冲输出流包括字节缓冲输出流 BufferedOutputStream 类和字符缓冲输出流 BufferedWriter 类。
package com.test;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.BufferedWriter;
public class Test
{
public static void main(String[] args)
{
File file;
FileReader fin;
FileWriter fout;
BufferedReader bin;
BufferedWriter bout;
Scanner scanner = new Scanner(System.in);
System.out.println("请输入文件名,例如d:\\hello.txt");
String filename = scanner.nextLine();
try
{
file = new File(filename);//创建文件对象
if (!file.exists())
{
file.createNewFile();//创建新文件
fout = new FileWriter(file);//创建文件输出流对
}
else
fout = new FileWriter(file, true);//创建追加内容的文件输出流对象
fin = new FileReader(file);//创建文件输入流
bin = new BufferedReader(fin);//创建缓冲输入流
bout = new BufferedWriter(fout);//创建缓冲输出流
System.out.println("请输入数据,最后一行为字符‘0’结束。");
String str = scanner.nextLine();//从键盘读取待输入字符串
while (!str.equals("0"))
{
bout.write(str);//输出字符串内容
bout.newLine();//输出换行符
str = scanner.nextLine();//读下一行
}
bout.flush();//刷新输出流
bout.close();//关闭缓冲输出流
fout.close();//关闭文件输出流
System.out.println("文件写入完毕!");
//重新将文件内容显示出来
System.out.println("文件" + filename + "的内容是:");
while ((str = bin.readLine()) != null)
System.out.println(str);//读取文件内容并显示
bin.close();//关闭缓冲输入流
fin.close();//关闭文件输入流
}
catch (IOException e)
{e.printStackTrace();}
}
}
运行结果:
请输入文件名,例如d:\hello.txt
d:\hello.txt
请输入数据,最后一行为字符‘0’结束。
fwfwfw
0
文件写入完毕!
文件d:\hello.txt的内容是:
fwfwfw
打印流、数据操作流和系统类System
打印流
Java提供了两种打印流:PrintStream(字节打印流),PrintWriter(字符打印流)。
package com.test;
import java.io.PrintWriter;
public class Test
{
public static void main(String args[])
{
PrintWriter out = null;
// 通过System.out对PrintWriter实例化
out = new PrintWriter(System.out);
// 向屏幕上输出
out. print ("Hello World!");
out.close();
}
}
输出:
Hello World!
package com.test;
import java.io.PrintWriter;
import java.io.File;
import java.io.IOException;
import java.io.FileWriter;
public class Test
{
public static void main(String args[])
{
PrintWriter out = null ;
File f = new File("d:\\hello.txt") ;
try
{
out = new PrintWriter(new FileWriter(f)) ;
}
catch (IOException e)
{
e.printStackTrace();
}
// 由FileWriter实例化,则向文件中输出
out. print ("Hello World!"+"\r\n");
out.close() ;
}
}
数据操作流
数据流是Java提供的一种装饰类流,建立在实体流基础上,让程序不考虑所占字节的个数就能正确完成读写操作。数据流类分为DataInputStream类和DataOutputStream类,分别为数据输入流和数据输出流。
package com.test;
import java.io.FileOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.File;
import java.io.DataInputStream;
public class Test
{
public static void main(String args[])
{
File file=new File("data.txt");
try
{
FileOutputStream out=new FileOutputStream(file);
DataOutputStream outData=new DataOutputStream(out);
outData.writeBoolean(true);
outData.writeChar('A');
outData.writeInt(10);
outData.writeLong(88888888);
outData.writeFloat(3.14f);
outData.writeDouble(3.1415926897);
outData.writeChars("hello,every one!");
}
catch(IOException e){}
try
{
FileInputStream in=new FileInputStream(file);
DataInputStream inData=new DataInputStream(in);
System.out.println(inData.readBoolean());//读取boolean数据
System.out.println(inData.readChar());//读取字符数据
System.out.println(inData.readInt()); //读取int数据
System.out.println(inData.readLong()); //读取long数据
System.out.println(+inData.readFloat()); //读取float数据
System.out.println(inData.readDouble()); //读取double数据
char c = '\0';
while((c=inData.readChar())!='\0')//读入字符不为空
System.out.print(c);
}
catch(IOException e){}
}
}
输出:
true
A
10
88888888
3.14
3.1415926897
hello,every one!
系统类System
package com.test;
import java.io.FileReader;
import java.io.Reader;
import java.io.File;
public class Test
{
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
File f = new File("d:"+File.separator+"hello.txt");
Reader input = null;
input = new FileReader(f);
char c[] = new char[1024];
int len = input.read(c);
input.close();
System.out.println("内容为:"+new String(c,0,len));
}
}
输出:
内容为:Hello World!
内存流和扫描流
内存流
字节数组流
package com.test;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.OutputStream;
public class Test
{
public static void main(String[] args) throws Exception
{
String tmp = "abcdefghijklmnopqrstuvwxyz";
byte[] src = tmp.getBytes(); // src为转换前的内存块
ByteArrayInputStream input = new ByteArrayInputStream(src);
ByteArrayOutputStream output = new ByteArrayOutputStream();
new Test().transform(input, output);
byte[] result = output.toByteArray(); // result为转换后的内存块
System.out.println(new String(result));
}
public void transform(InputStream in, OutputStream out)
{
int c = 0;
try
{
while ((c = in.read()) != -1) // read在读到流的结尾处返回-1
{
int C = (int) Character.toUpperCase((char) c);
out.write(C);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
输出:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
字符数组流
( 1) CharArrayReader 实际上是通过字符数组保存数据的。
( 2) 在构造函数中有 buf, 通过 buf 来创建对象。
( 3) read()函数读取下一个字符。
package com.test;
import java.io.CharArrayReader;
import java.io.IOException;
public class Test
{
private static final int LEN = 5;
// 对应英文字母“abcdefghijklmnopqrstuvwxyz”
private static final char[] ArrayLetters = new char[] {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t', 'u','v','w','x','y','z'};
public static void main(String[] args) {
tesCharArrayReader() ;
}
/**
* CharArrayReader的API测试函数
*/
private static void tesCharArrayReader() {
try {
// 创建CharArrayReader字符流,内容是ArrayLetters数组
CharArrayReader car = new CharArrayReader(ArrayLetters);
// 从字符数组流中读取5个字符
for (int i=0; i<LEN; i++) {
// 若能继续读取下一个字符,则读取下一个字符
if (car.ready() == true) {
// 读取“字符流的下一个字符”
char tmp = (char)car.read();
System.out.printf("%d : %c\n", i, tmp);
}
}
// 若“该字符流”不支持标记功能,则直接退出
if (!car.markSupported()) {
System.out.println("make not supported!");
return ;
}
// 标记“字符流中下一个被读取的位置”。即--标记“f”,因为因为前面已经读取了5个字符,所以下一个被读取的位置是第6个字符”
// (01), CharArrayReader类的mark(0)函数中的“参数0”是没有实际意义的。
// (02), mark()与reset()是配套的,reset()会将“字符流中下一个被读取的位置”重置为“mark()中所保存的位置”
car.mark(0);
// 跳过5个字符。跳过5个字符后,字符流中下一个被读取的值应该是“k”。
car.skip(5);
// 从字符流中读取5个数据。即读取“klmno”
char[] buf = new char[LEN];
car.read(buf, 0, LEN);
System.out.printf("buf=%s\n", String.valueOf(buf));
// 重置“字符流”:即,将“字符流中下一个被读取的位置”重置到“mark()所标记的位置”,即f。
car.reset();
// 从“重置后的字符流”中读取5个字符到buf中。即读取“fghij”
car.read(buf, 0, LEN);
System.out.printf("buf=%s\n", String.valueOf(buf));
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出:
0 : a
1 : b
2 : c
3 : d
4 : e
buf=klmno
buf=fghij
字符串流
public class Test
{
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
FileReader fr;
fr=new FileReader("e:\\test1.txt");
File file =new File("e:\\test2.txt");
FileWriter fos=new FileWriter(file);
BufferedReader br=new BufferedReader(fr);
BufferedWriter bw=new BufferedWriter(fos);
String str=null;
while((str=br.readLine())!=null) {
bw.write(str+"\n");
}
br.close();
bw.close();
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
扫描流
可以使用 Scanner 类实现基本的数据输入, 其中最简单的方法就是直接使用 Scanner类的 next()方法来实现数据的输入。
但是如果输入的数据中有空格,而输出的数据只有空格之前的那一段,因为Scanner类将空格当成了分隔符。
public class Test
{
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scan=null;
File f=new File("E:"+File.separator+"test.txt");
try {
scan=new Scanner(f);
}catch (Exception e) {
// TODO: handle exception
}
StringBuffer str=new StringBuffer();
while(scan.hasNext()) {
str.append(scan.next()).append("\n");
}
System.out.println("文件内容为:\n"+str);
}
}
过滤器流
基本输入流只能读取字节以及字符,但是过滤器流能够读取整数值,双精度值以及字符串。
对象序列化
对象序列化指的是把一个对象变成二进制的数据流的一种方法, 通过对象序列化可以方便地实现对象的传输或者存储。要实现对一个类的对象序列化处理, 则对象所在的类就必须实现 Serializable 接口。
实现序列化就是使用对象输出流输出序列化对象, 而反序列化就是使用对象输入流输入对象。
package com.test;
import java.io.File;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.Serializable;
public class Test {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
File f = new File("d:"+File.separator+"hello.txt");
ObjectOutputStream oos=null;
OutputStream out = new FileOutputStream(f);
oos = new ObjectOutputStream(out);
oos.writeObject(new Person("张三",30));
oos.close();
}
}
class Person implements Serializable{
private String name;
private int age;
public Person(String name,int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "姓名:"+this.name+";年龄:"+this.age;
}
}
package com.test;
import java.io.File;
import java.io.ObjectInputStream;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.Serializable;
public class Test {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
File f = new File("d:"+File.separator+"hello.txt");
ObjectInputStream ois=null;
InputStream input = new FileInputStream(f);
ois = new ObjectInputStream(input);
Object obj = ois.readObject();
ois.close();
System.out.println(obj);
}
}
class Person implements Serializable{
private String name;
private int age;
public Person(String name,int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "姓名:"+this.name+";年龄:"+this.age;
}
}
输出:
姓名:张三;年龄:30
transient 关键字
Serializable 接口实现的操作实际上是将一个对象中的全部属性序列化, 当进行序列化操作时, 如果一个对象中的某个属性不希望被序列化, 则可以使用关键字 transient 声明。