Flie类
用来将文件或者文件夹封装成对象
方便对文件与文件夹的属性信息进行操作
File对象可以作为参数传递给流的构造函数
File类的常见方法:
1.创建。
boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。
和输出流不一样,输出流对象一建立就创建文件,而且当文件已经存在时会覆盖原文件。
boolean mkdir():创建文件夹。
boolean mkdirs():创建多级文件夹。
2.删除。
boolean delete():删除失败返回false。
void deleteOnExit():在程序退出时删除指定文件。
3.判断。
canExecute():文件是否能执行。
boolean exists():文件是否存在。
isFile():是否是文件
isDirectory():是否是文件夹
isHidden():是否是隐藏文件
isAbsolute():是否是绝对路径
4.获取信息。
getName():
getPath():
getParent():
getAbsolutePath():
lastModified():
length():
renameTo():修改名字。
import java.io.*;
class FileDemo
{
public static void main(String[] args) throws IOException
{
consMethod();
method_1();
method_2();
method_3();
method_4();
}
public static void method_5()
{
File f1 = new File("c:\\Test.java");
File f2 = new File("c:\\haha.java");
sop("rename:"+f1.renameTo());
}
public static void method_4()
{
File f = new File("a.txt");
sop("path:"+f.getPath());
sop("abspath:"+f.getAbsolutePath());
sop("Parent:"+f.getParent());//该方法返回的是绝对路径下的父目录。如果是相对路径,返回null。
//如果相对路径中有上一层目录,那么该目录就是返回结果。
}
public static void method_3()
{
File f = new File("file.txt");
//记住在判断文件对象是否是文件或目录时,必须要先判断该文件对象封装的内容是否存在。
//通过exists判断。
sop("dir:"+f.isDirectory());
sop("file:"+f.isFile());
}
public static void method_1()throws IOException
{
File f = new File("file.txt");
sop("create:"+f.createNewFile());
sop("delete:"+f.delete());
}
public static void method_2()
{
File f= new File("file.txt");
sop("execute:"+f.canExecute());
sop("exists:"+f.exists());
//创建文件夹
File dir = new File("abc");
sop("mkdir:"+dir.mkdir());
}
//创建File对象
public static void consMethod()
{
//将a.txt封装成file对象。可以将已有的和未出现的文件或文件夹封装成对象。
File f1 = new File("a.txt");
File f2 = new File("c:\\abc","b.txt");
File d = new File("c:\\abc");
File f3 = new File(d,"c.txt");
sop("f1:"+f1);
sop("f2:"+f2);
sop("f3:"+f3);
File f4 = new File("c:"+File.separator+"abc"+File.separator+"zzz"+File.separator+"a.txt");//separator 跨平台分隔符
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
文件列表list功能。
import java.io.*;
class FileDemo2
{
public static void main(String[] args)
{
//listRootsDemo();
//listDemo();
File dir = new File("E:\\JAVA\\day18");
String[] arr = dir.list(new FilenameFilter()
{
public boolean accept(File dir,String name)
{
return name.endsWith(".bmp");
}
});
for(String name:arr)
{
System.out.println(name);
}
}
public static void listRootsDemo()
{
File[] files = File.listRoots();
for(File f: files)
{
System.out.println(f);
}
}
public static void listDemo()
{
File f = new File("c:\\");
String[] names = f.list();//调用list方法的file对象必须是封装了一个目录,该目录还必须存在。
for(String name:names)
{
System.out.println(name);
}
}
}
列出目录下所有内容-递归
列出指定目录下文件或者文件夹,包含子目录中的内容。
也就是列出指定目录下所有内容。
因为目录中还有目录,只要使用同一个列出目录功能的函数完成即可。
在列出过程中出现的还是目录的话,可以再次调用本功能,
也就是函数自身调用自身,
这种表现形式,称之为递归。
递归要注意:
1.限定条件。
2.要注意递归的次数,尽量避免内存溢出。
import java.io.*;
class FileDemo3
{
public static void main(String[] args)
{
File dir = new File("e:\\java");
showDir(dir,0);
}
public static String getLevel(int level)
{
StringBuilder sb = new StringBuilder();
for(int x=0;x<level;x++)
{
sb.append("|--");
}
return sb.toString();
}
public static void showDir(File dir,int level)
{
System.out.println(getLevel(level)+dir.getName());
level++;
File[] files = dir.listFiles();
for(int x=0;x<files.length;x++)
{
if(files[x].isDirectory())
showDir(files[x],level);
System.out.println(getLevel(level)+files[x]);
}
}
}
删除带内容的目录
/*
删除一个带内容的目录。
删除原理:
在windows中,删除目录是从里往外删除的。
既然是从里往外删除,就需要用到递归。
*/
import java.io.*;
class RemoveDir
{
public static void main(String[] args)
{
File dir = new File("c:\\dir");
}
public static void removeDir(File dir)
{
File[] files = dir.listFiles();
for(int x=0;x<files.length;x++)
{
if(files[x].isDirectory())
removeDir(files[x]);
else
System.out.println(files[x].toString()+"::"+files[x].delete());
}
System.out.println(dir.delete());
}
}
创建java文件列表
/*
练习:
将一个指定目录下的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("e:\\java");
List<File> list = new ArrayList<File>();
fileToList(dir,list);
System.out.println(list.size());
File file = new File(dir,"javalist.txt");
writeToFile(list,file.toString());
}
public static void fileToList(File dir,List<File>list)
{
File[] files = dir.listFiles();
for(File file:files)
{
if(file.isDirectory())
fileToList(file,list);
else
{
if(file.getName().endsWith(".java"))
list.add(file);
}
}
}
public static void writeToFile(List<File> 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 e;
}
finally
{
try
{
if(bufw !=null)
bufw.close();
}
catch (IOException e)
{
throw e;
}
}
}
}
Properties简述
Properties是hashtable的子类。
也就是说它具备map集合的特点。而且它里面存储的键值对都是字符串。
是集合和IO技术相结合的集合容器。
该对象的特点:可以用于键值对形式的配置文件。
那么在加载数据时,需要数据有固定格式:键=值。
Properties存取
import java.io.*;
import java.util.*;
class PropertiesDemo
{
public static void main(String[] args) throws IOException
{
setAndGet();
method_1();
loadDemo();
}
//设置和获取元素。
public static void setAndGet()
{
Properties prop = new Properties();
prop.setProperty("zhangsan","30");
prop.setProperty("lisi","39");
//System.out.println(prop);
String value = prop.getProperty("lisi");
System.out.println(value);
prop.setProperty("lisi",89+"");
Set<String> names = prop.stringPropertyNames();
for(String s : names)
{
System.out.println(s+"::"+prop.getProperty(s));
}
}
public static void loadDemo()throws IOException
{
FileInputStream fis = new FileInputStream("info.txt");
Properties prop = new Properties();
//将流中数据加载进集合。
prop.load(fis);
prop.setProperty("wangwu","60");
FileOutputStream fos = new FileOutputStream("info.txt");
prop.store(fos,"haha");
System.out.println(prop);
prop.list(System.out);
fos.close();
fis.close();
}
//想要将info.txt中键值数据存储到集合中进行操作。
/*
1.用一个流和info。txt文件关联。
2.读取一行数据,将该行数据用“=”进行切割。
3.等号左边作为键,右边作为值,存入到Properties集合中即可。
*/
public static void method_1()throws IOException
{
BufferedReader bufr = new BufferedReader(new FileReader("info.txt")) ;
String line = null;
Properties prop = new Properties();
while((line=bufr.readLine())!=null)
{
String[] arr = line.split("=");
System.out.println(arr[0]+"..."+arr[1]);
prop.setProperty(arr[0],arr[1]);
}
bufr.close();
System.out.println(prop);
}
}
Properties练习
/*
用于记录应用程序运行次数。
如果使用次数已到,那么给出注册提示。
很容易想到的是:计数器。
该计数器定义在程序中,随着程序的运行而在内存中存在,并进行了自增。
可是随着该应用程序的退出,该计数器也在内存中消失了。
下一次再启动该程序,又重新开始从0计数。
这样不是我们想要的。
程序即使结束,该计数器的值也存在。
下次程序启动会先加载该计数器的值并加1后再重新存储起来。
所以要建立一个配置文件,用于记录该软件的使用次数。
该配置文件使用键值对的形式。
这样便于阅读数据并操作数据。
键值对数据是map集合。
数据是以文件形式存储的,使用io技术。
那么map+io-->properties。
配置文件可以实现应用程序数据的共享。
*/
import 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)
{
System.out.println("您好,使用次数已到,拿钱!");
return;
}
}
count++;
prop.setProperty("time",count+"");
FileOutputStream fos = new FileOutputStream(file);
prop.store(fos,"");
fos.close();
fis.close();
}
}
IO包中的其他类
打印流
PrintWriter与PrintStream
可以直接操作输入流和文件。
/*
打印流:
该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:
PrintStream
构造函数可以接收的参数类型:
1.file对象:File
2.字符串路径:String
3.字节输出流:OutputStream
字符打印流:
PrintWtriter
构造函数可以接收的参数类型:
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(System.out,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.*;
class SequenceDemo
{
public static void main(String[] args) throws IOException
{
Vector<FileInputStream> v = new Vector<FileInputStream>();
v.add(new FileInputStream("c:\\1.txt"));
v.add(new FileInputStream("c:\\2.txt"));
v.add(new FileInputStream("c:\\3.txt"));
Enumeration<FileInputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("c:\\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();
}
}
把某个对象进行分割,再合并。
import java.io.*;
import java.util.*;
class SplitFile
{
public static void main(String[] args) throws IOException
{
splitFile();
merge();
}
public static void splitFile()throws IOException
{
FileInputStream fis = new FileInputStream("c:\\1.bmp");
FileOutputStream fos =null;
byte[] buf = new byte[1024*1024];
int len = 0;
int count = 1;
while((len=fis.read(buf))!=-1)
{
fos = new FileOutputStream("c:\\splitfiles\\"+(count++)+".part");
fos.write(buf,0,len);
fos.close();
}
fis.close();
}
public static void merge()throws IOException
{
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for(int x= 1;x<=3;x++)
{
al.add(new FileInputStream("c:\\spiltfiles\\"+x+".part"));
}
final Iterator<FileInputStream> it = al.iterator();
Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()
{
public boolean hasMoreElements();
{
return it.hasNext();
}
public FileInputStream nextElement()
{
return it.next();
}
};
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("c:\\spiltfiles\\0.bmp");
byte[] buf = new byte[1024];
int len = 0;
while((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
}
操作对象
ObjectInputStream与ObjectOutputStream
被操作的对象需要实现Serializable(标记接口)。
import java.io.*;
class ObjectStreamDemo
{
public static void main(String[] args) throws Exception
{
//writeObj();
readObj();
}
public static void readObj()throws Exception
{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
Person p = (Person)ois.readObject();
System.out.println(p);
ois.close();
}
public static void writeObj()throws IOException
{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
oos.writeObject(new Person("lisi",39));
oos.close();
}
}
import java.io.*; class Person implements Serializable { public static final long serialVersionUID = 42L; String name; transient int age; //age也没有被序列化。 static String country = "cn"; //静态成员不能被序列化。 Person(String name,int age,String country) { this.name = name; this.age = age; this.country = country; } public String toString() { return name+":"+age+":"+country; } }
RandomAccessFile
随机访问文件,自身具备读写的方法。
通过skipBytes(int x),seek(int x)来达到随机访问。
/* RandomAccessFile 该类不算是IO体系中子类。 而是直接继承自Object。 但是它是IO包中的成员,因为它具备读和写功能。 内部封装了一个数组,而且通过指针对数组元素进行操作。 可以通过getFilePointer获取指针位置。 同时可以通过seek改变指针的位置。 其实完成读写的原理就是内部封装了字节输入流和输出流。 通过构造函数可以看出该类只能操作文件。 而且操作文件还有模式:只读r,读写rw等。 如果模式为r,不会创建文件,会去读取一个已存在的文件,如果该文件不存在则会出现异常。 如果模式为rw,那么操作的文件不存在,会自动创建,如果存在,则不会覆盖。 */ import java.io.*; class RandomAccessFileDemo { public static void main(String[] args) throws IOException { //writeFile(); writeFile_2(); //readFile(); } public static void readFile()throws IOException { RandomAccessFile raf = new RandomAccessFile("ran.txt","r"); //调整对象中指针。 //raf.seek(4); //跳过指定的字节数。 //raf.skipBytes(4); byte[] buf = new byte[4]; raf.read(buf); String s = new String(buf); int age = raf.readInt(); System.out.println(s+":"+age); raf.close(); } public static void writeFile()throws IOException { RandomAccessFile raf = new RandomAccessFile("ran.txt","rw"); raf.write("李四".getBytes()); raf.writeInt(97); raf.close(); } public static void writeFile_2()throws IOException { RandomAccessFile raf = new RandomAccessFile("ran.txt","rw"); raf.seek(4); raf.write("周期".getBytes()); raf.writeInt(103); raf.close(); } }
管道流
PipedInputStream和PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用。
import java.io.*; class PipedInputStreamDemo { 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(); } } class Read implements Runnable { private PipedInputStream in; Read(PipedInputStream in) { this.in =in; } public void run() { try { byte[] buf = new byte[1024]; int len = in.read(buf); 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 { out.write("piped lai la".getBytes()); out.close(); } catch (IOException e) { throw new RuntimeException("管道输出流失败"); } } }
操作基本数据类型
DataInputStream与DataOutputStream
/* DataInputStream与DataOutputStream 可以操作基本数据类型的流对象。 */ import java.io.*; class DataStreamDemo { public static void main(String[] args) throws IOException { //writeData(); //readData(); //writeUTFDemo(); readUTFDemo(); } public static void writeData()throws IOException { DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt")); dos.writeInt(234); dos.writeBoolean(true); dos.writeDouble(9887.543); 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+":"+b+":"+d); dis.close(); } public static void writeUTFDemo()throws IOException { DataOutputStream dos = new DataOutputStream(new FileOutputStream("utfdata.txt")); dos.writeUTF("你好"); dos.close(); } public static void readUTFDemo()throws IOException { DataInputStream dis = new DataInputStream(new FileInputStream("utfdata.txt")); String s = dis.readUTF(); System.out.println(s); dis.close(); } }
操作字节数组
ByteArrayInputStream与ByteArrayOutputStream
/* 用于操作字节数组的流对象。 ByteArrayInputStream:在构造的时候,需要接收数据源,而且数据源是一个字节数组。 ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的数组, 这就是数据目的地。 因为这两个流对象都操作数组,并没有使用系统资源,所以不用进行close关闭。 在流操作规律讲解时: 源设备: 键盘 System.in,硬盘 FileStream,内存 ArrayStream。 目的设备: 控制台System.out,硬盘FileStream,内存 ArrayStream。 用流的读写思想来操作数组。 */ import java.io.*; class ByteArrayStreamDemo { public static void main(String[] args) { //数据源。 ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFG".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()); } }
操作字符数组
CharArrayReader与CharArrayWriter
操作字符串
StringReader与StringWriter
字符编码
字符流的出现为了方便操作字符。
更重要的是加入了编码转换。
通过子类转换流来完成。
InputStreamReader
OutputStreamWriter
在两个对象进行构造的时候可以加入字符集。
import java.io.*; class EncodeStream { public static void main(String[] args) throws IOException { //writeText(); readText(); } public static void writeText()throws IOException { OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk.txt"),"UTF-8"); osw.write("你好"); osw.close(); } public static void readText()throws IOException { InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.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(); } }
编码:字符串变字节数组。
解码:字节数组变字符串。
String-->byte[]; str.getBytes(charsetName);
byte[]-->String; new String(byte[],charsetName);
import java.util.*; class EncodeDemo { public static void main(String[] args) throws Exception { String s = "你好"; byte[] b1 = s.getBytes("GBK"); System.out.println(Arrays.toString(b1)); String s1 = new String(b1,"GBK"); System.out.println(s1); } }
练习:
/* 有五个学生,每个学生有3门课的成绩, 从键盘输入以上数据(包括姓名,三门课成绩), 输入的格式:如:zhangsan,30,40,50,并计算出总成绩, 并把学生的信息和计算出的总分按高低顺序存放在磁盘文件”stud。txt“中。 1.描述学生对象。 2.定义一个可以操作学生对象的工具类。 思想: 1.通过获取键盘录入的一行数据,并将该行数据中的信息取出封装成学生对象。 2.因为学生对象有很多,那么就需要存储,使用到集合,因为要对学生的总分排序, 所以可以使用TreeSet。 3.将集合中的信息写入到一个文件中。 */ import java.io.*; import java.util.*; class StudentInfoTest { public static void main(String[] args) throws Exception { Comparator<Student> cmp = Collections.reverseOrder(); Set<Student> stus = StudentInfoTool.getStudent(cmp); StudentInfoTool.write2File(stus); } } class Student implements Comparable<Student> { private String name; private int ma,cn,en; private int sum; Student(String name,int ma,int cn,int en) { this.name = name; this.ma = ma; this.cn = cn; this.en = en; sum = ma+cn+en; } public int compareTo(Student s) { int num = new Integer(this.sum).compareTo(new Integer(s.sum)); if(num==0) return this.name.compareTo(s.name); return num; } public String getName() { return name; } public int getSum() { return sum; } public int hashCode() { return name.hashCode()+sum*78; } public boolean equals(Object obj) { if(!(obj instanceof Student)) throw new ClassCastException("类型不匹配"); Student s = (Student)obj; return this.name.equals(s.name) && this.sum==s.sum; } public String toString() { return "student["+name+", "+ma+", "+cn+", "+en+"]"; } } class StudentInfoTool { public static Set<Student> getStudent()throws IOException { return getStudent(null); } public static Set<Student> getStudent(Comparator<Student> cmp)throws IOException { BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); String line = null; Set<Student> stus = null; if(cmp==null) stus = new TreeSet<Student>(); else stus = new TreeSet<Student>(cmp); while((line=bufr.readLine())!=null) { if("over".equals(line)) break; String[] info = line.split(","); Student stu = new Student(info[0],Integer.parseInt(info[1]),Integer.parseInt(info[2]),Integer.parseInt(info[3])); stus.add(stu); } bufr.close(); return stus; } public static void write2File(Set<Student> stus)throws IOException { BufferedWriter bufw = new BufferedWriter(new FileWriter("stuinfo.txt")); for(Student stu : stus) { bufw.write(stu.toString()+"\t"); bufw.write(stu.getSum()+""); bufw.newLine(); bufw.flush(); } bufw.close(); } }