-----------android培训、java培训、java学习型技术博客、期待与您交流!------------
File类
1、用来将文件或者文件夹封装成对象, 方便对文件与文件夹的属性信息进行操作, File对象可以作为参数传递给流的构造函数
//将a.txt封装成File对象,可以将已有的和未出现的文件或者文件夹封装成对象
File f1 = newFile(“a.txt”); //打印f1时打印的是a.txt , 是相对路径
//将文件的父目录和文件一起封装成对象
File f2 = newFile(“c:\\abc”,b.txt); 打印f2时打印的是c:\abc”\b.txt, 绝对路径。
//将文件父目录或者子目录作为参数传递到文件对象
File d = newFile(“c:\\abc”);
File f3 = newFile(d,”c.txt”); //与上一种方式是一样的,只是写法不同
//将\\目录分隔符使用跨平台的方式的写法:File.separator
File f4 = newFile(“c:”+File.separator+”abc”+File.separator+”a.txt”);
2、File类中的常用方法
1)创建
boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false和输出流不一样,输出流对象建立创建文件。而且文件已经存在,会覆盖
boolean mkdir():创建文件夹
boolean mkdirs():创建多级文件夹
2)删除
boolean delete();删除失败返回false
void deleteOnExit();在程序退出时删除指定文件
3)判断
boolean exists():文件是否存在。在流读取文件时可以先判断文件是否存在,这就是将文件封装成对象的好处
isFile():是否是文件
isDirectory();是否是目录
isHidden();是否隐藏
isAbsolute();//判断文件是否为绝对路径,如果是文件不存在也会返回true
注意:记住在判断文件对象是否是文件或者目录时,必须先判断该文件是否存在,通过exists判断
4)获取信息
getName();获取文件名称
getPath();获取相对路径,封装什么路径获取什么路径
getParent();获取父目录 该方法返回的是绝对路径下的父目录,如果文件是相对路径则返回null 如果相对路径中有上一层目录,该目录就是返回结果
getAbsolutePath();获取绝对路径
long lastModified();最后一次修改时间
long length();文件大小
5)其他
File[] listRoots:获取系统有效根盘符
String[] list:获取指定目录下的所有文件和文件夹的名称,包含隐藏的。调用list方法的File对象必须是封装了的一个目录,必须存在
File[] listFiles:返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录一般用File[] listFiles比较多
3、递归:就是函数自身调用自身,简单说就是功能内部又用到该功能,但传递的参数值不确定。在使用递归是一般要单独定义一个方法
注意事项:一定要定义递归的条件;递归的次数不要过多,否则会出现StackOverflowError栈内存溢出错误,原因是递归时,在栈内存不断创建对象方法,只有最里面的方法执行完才会执行外边的
/*
练习:
将指定目录下的java文件的绝对路径存储到一个文本文件中,
建立一个文件列表文件。
思路:因为要找到目录下的所有文件,就要使用递归操作
获取文件的绝对路径,存储到一个集合中
遍历集合,通过流写入方式将文件的绝对路径存储到一个文件中
*/
import java.util.*;
import java.io.*;
class Demo3
{
public static void main(String[] args)
{
ArrayList list = new ArrayList();
File dir = new File("e:\\java0217");
filePath(dir,list);
System.out.println(list.size());//打印集合中是否有元素
File f = new File(dir,"FileDirectory.txt");//新建文件对象,作为写入流的目的地
writeToFile(list,f);
}
public static void filePath(File dir,ArrayList list)
{
File[] files = dir.listFiles();
for(File file : files)
{
if(file.isDirectory())//判断是否为文件夹,是递归调用
filePath(file,list);
else
{
if(file.getName().endsWith(".java"))//获取文件名称的后缀名是不是.jaja文件
{
String path = file.getAbsolutePath();//获取找到的文件的绝对路径
list.add(path);//将绝对路径存入集合
}
}
}
}
public static void writeToFile(ArrayList list,File f)
{
BufferedWriter bw = null;
try
{
bw = new BufferedWriter(new FileWriter(f));
for(String file : list)
{
bw.write(file);
bw.newLine();
bw.flush();
}
}
catch (IOException e)
{
throw new RuntimeException("写入文件失败");
}
finally
{
try
{
if(bw!=null)
bw.close();
}
catch (IOException e)
{
throw new RuntimeException("关闭流失败");
}
}
}
}
java.util.Properties:是集合中和io技术相结合的容器
1、properties 是hashtable 的子类,也就是说它具备map集合的特点,而且它里面存储的键值对都是字符串,可以用于键值对形式的配置文件,那么在加载数据时,需要数据有固定格式:键=值
2、常见方法:
*getProperties(String key):获取值
*setProperties(String key,String value)://设置值
*load(InputStream inStream); //从字节输入流中读取属性列表(键和元素对)
*load(Reader reader); //从字符输入流中读取属性列表(键和元素对)
*store(OutputStream out , String comments); //将此 Properties
表中的属性列表(键和元素对)写入字节输出流,comments为描述信息。例如haha
*store(Writer wri ,String comments; //将此 Properties
表中的属性列表(键和元素对)写入字符输出流
import java.util.*;
import java.io.*;
class PropertiesDemo
{
public static void main(String[] args)throws IOException
{
//setAndGet();
//method();//模拟properties中的load方法
fileLoad();
}
public static void fileLoad()throws IOException
{
Properties prop = new Properties();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("Info.txt"));
prop.load(bis);
prop.setProperty("lisi","21");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Info.txt"));
prop.store(bos,"haha");
System.out.println(prop);
bis.close();
bos.close();
}
/*
演示,如何将流中的数据存储到集合中
要求:将Info.txt中键值数据存储到集合中
1、用一个流和Info.txt相关联
2、读取一行数据,将该行数据用“=”进行切割
3、等号左边作为键,右边作为值。在存入properties集合中即可
*/
public static void method()throws IOException
{
BufferedReader br = new BufferedReader(new FileReader("Info.txt"));
Properties prop = new Properties();
String line =null;
while((line=br.readLine())!=null)
{
String[] str = line.split("=");
prop.setProperty(str[0],str[1]);
}
br.close();
System.out.println(prop);
}
//设置和获取元素
public static void setAndGet()
{
Properties prop = new Properties();
prop.setProperty("zhangsan","33");
prop.setProperty("lisi","50");
String value = prop.getProperty("lisi");
//System.out.println(value);
prop.setProperty("lisi","20");
Set names = prop.stringPropertyNames();
for(String name : names)
{
System.out.println(name+"::"+prop.getProperty(name));
}
}
}
/*
用于记录应用程序运行次数
如果使用次数已到,那么给出注册提示。
思路:
1、使用硬盘上的配置文件记录软件运行次数,配置文件以键值形式存储 要使用到Map集合
2、必须通过输入流的方式来关联配置文件,要使用到IO
3、这样就可以使用集合与IO的集合技术 Properties
4、程序没运行一次需要一个计数器加一次,在存回配置文件 使用输出流
*/
import java.util.*;
import java.io.*;
class Demo55
{
public static void main(String[] args) throws IOException
{
method();
}
public static void method()throws IOException
{
File f = new File("protect.ini");//将文件封装成对象
if(!f.exists())
f.createNewFile();//不存在就创建
BufferedReader br = new BufferedReader(new FileReader(f));
Properties prop = new Properties();
prop.load(br);
int count=0;
String value = prop.getProperty("time");
if(value!=null)
{
count = Integer.parseInt(value);
if(count>=5)
System.out.println("使用期限已到,请注册");
count++;
}
else
{
count =1;
}
prop.setProperty("time",count+"");
FileWriter fw = new FileWriter(f);
prop.store(fw,"heihei");
br.close();
fw.close();
}
}
printStream:打印流
1、打印流:该流提供了打印方法,可以将各种数据类型的数据都原样打印
2、分类:字节打印流PrintStream 和字符打印流 PrintWriter
3、字节打印流:PrintStream 构造函数可以接收的参数类型:
1)file对象。File
2)字符串路径。String
3)字节输出流。OutputStream
4、PrintWriter字符打印流:推荐使用字符打印流,功能齐全 。构造函数可以接收的参数类型:
1)file对象。File
2)字符串路径。String
3)字节输出流。OutputStream
4)字符输出流。Writer
//打印流 PrintWriter
import java.io.*;
class Demo6
{
public static void main(String[] args)throws IOException
{
method();
}
public static void method()throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(new FileWriter("a.txt"),true);//加上true实现自动刷新
String line=null;
while((line=br.readLine())!=null)
{
if(line.equals("end"))
break;
pw.println(line.toUpperCase());
}
br.close();
pw.close();
}
}
SequenceInputStream:合并流
1、将其他输入流关联的文件对象进行逻辑串联,它从输入流的有序集合开始,从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流文件的末尾为止,将多个输入流合并成一个输入流,实现数据的合并
2、好处:可以更方便的操作多个读取流,其实这个序列流内部会有一个有序集合容器,用于存储多个输入流对象
3、该对象的构造函数参数是枚举,想要获取枚举,需要Vector集合,但是Vector集合效率低。可以使用ArrayList集合,但是ArrayList集合只有迭代,因为枚举是一个接口,可以使用匿名内部类的方式创建枚举对象,复写hasMoreElements()和nexElement()着两个方法。然后分别返回ArrayList集合迭代器的it.hasNext()和it.nex(),在将枚举传递给Sequence的构造函数
4、合并原理:多个读取流对应一个输出流
切割原理:一个读取流对应多个输出流
import java.io.*;
import java.util.*;
class Demo8
{
public static void main(String[] args)throws IOException
{
//splitFile();
sequence();
}
public static void splitFile()throws IOException//切割图片
{
FileInputStream fis = new FileInputStream("e:\\java0217\\day20\\10.bmp");
FileOutputStream fos = null;
byte[] buf = new byte[1024*1024];//每次读取一兆数据存储到数组
int len = 0;
int x =1;
while((len=fis.read(buf))!=-1)
{
fos = new FileOutputStream("e:\\java0217\\day20\\splitFile\\"+(x++)+".part");
fos.write(buf,0,len);
fos.close();
}
fis.close();
}
public static void sequence()throws IOException//合并图片
{
//因为要用到Enumeration,可以使用Vector。由于Vector是同步的,效率低,所以用ArrayList
//但是ArrayList只有迭代器,只能使用匿名内部类的方式,复写Enumeration的方法,返回ArrayList的元素
ArrayList al = new ArrayList();
for(int x=1;x<=5;x++)
{
al.add(new FileInputStream("E:\\java0217\\day20\\splitFile\\"+x+".part"));
}
Iterator it = al.iterator();
Enumeration en =new Enumeration()
{
public boolean hasMoreElements()
{
return it.hasNext();
}
public FileInputStream nextElement()
{
return it.next();
}
};
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("E:\\java0217\\day20\\splitFile\\pic.jpg");
byte[] buf = new byte[1024];
int len =0;
while((len=sis.read(buf))!=-1)
{
fos.write(buf);
}
sis.close();
fos.close();
}
}
对象的序列化
1、java.io.ObjectOutputStream:将 Java 对象的基本数据类型和图形写入 OutputStream,可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。
2、java.io.ObjectInputStream
//对象的序列化
//ObjectOutputStream序列化和ObjectInputStream 反序列化
import java.io.*;
class ObjectStreamDemo1
{
public static void main(String[] args) throws Exception
{
//writeObj();
readObj();
}
public static void writeObj()throws IOException//ObjectOutputStream 写入的基本数据和对象进行序列化
{
FileOutputStream fos = new FileOutputStream("obj.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(new Person("lisi",22));//使用 ObjectOutputStream 将对象写入文件
oos.close();
}
public static void readObj()throws Exception//ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化
{
FileInputStream fis = new FileInputStream("obj.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
Person p = (Person)ois.readObject();//从 ObjectInputStream 读取对象
System.out.println(p);
}
}
class Person implements Serializable//只有实现Serializable接口对象才能被序列化和反序列化,它只是对象序列化的一个标记接口
{
public static final long serialVersionUID = 40L;//可序列化类显式声明 serialVersionUID
private String name;
transient int age;//transient 可以用来声明age不能被序列化,age只存在于对内存中
Person(String name,int age)
{
this.name=name;
this.age=age;
}
public String toString()
{
return name+":"+age;
}
}
RandomAccessFile随机读写访问
1、随机访问文件,自身具备读写的方法
2、通过skipBytes(intx),seek(int x)来达到随机访问,该类不算是io体系中子类,而是直接继承Object,但是它是io包中的成员,因为它具备读和写功能,内部封装了一个数组,而且通过指针对数组的元素进行操作。可以同getFilePointer获取指针位置,同时可以通过seek改变指针的位置
其实完成读写的原理就是内部封装了字节输入、输出流。
通过构造函数可以看出,该类只能操作文件,而且文件还有模式 r读 rw读写
如果模式为读r,不会创建文件,会去读取一个已存在的文件,如果该文件不存在,则会出现异常
如果模式为读取 rw,要操作的文件不存在,会自动创建,如果存在就不会被覆盖
import java.io.*;
class RandomAccessFileDemo
{
public static void main(String[] args)throws IOException
{
write();
read();
}
public static void write()throws IOException
{
RandomAccessFile raf = new RandomAccessFile("a.txt","rw");
raf.write("张三".getBytes());
raf.writeInt(97);
raf.write("李四".getBytes());
raf.writeInt(99);
raf.seek(8*3);//在指定的指针位置写入数据
raf.write("赵六".getBytes());
raf.writeInt(108);
}
public static void read()throws IOException
{
RandomAccessFile raf = new RandomAccessFile("a.txt","r");
raf.seek(8*3);//改变指针位置,可以直接获取赵六信息
byte[] buf = new byte[4];//一个汉字两个字节
int len = raf.read(buf);
String name = new String(buf);
int age = raf.readInt();//readInt一次读取一个整数
System.out.println(name+"..."+age);
}
}
DataStream操作基本数据的字节流对象
DataInputStream和DataOutputStream
//DataStream操作基本数据的流对象
//DataInputStream DataoutputStream
import java.io.*;
class DataStream
{
public static void main(String[] args)throws IOException
{
//writeData();
//readData();
writeUTF();
readUTF();
}
public static void writeData()throws IOException
{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
dos.writeInt(3030);
dos.writeBoolean(true);
dos.writeDouble(123.456);
dos.close();
}
public static void readData()throws IOException
{
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
int i = dis.readInt();//读取是要按照写入是的顺序进行读取,否则数据不正确
boolean b = dis.readBoolean();
double d = dis.readDouble();
System.out.println(i);
System.out.println(b);
System.out.println(d);
dis.close();
}
public static void writeUTF()throws IOException //对UTF解码是只能用其对应的方法
{
DataOutputStream dos = new DataOutputStream(new FileOutputStream("UTF.txt"));
dos.writeUTF("哈哈");
dos.close();
}
public static void readUTF()throws IOException
{
DataInputStream dis = new DataInputStream(new FileInputStream("UTF.txt"));
String str = dis.readUTF();
System.out.println(str);
dis.close();
}
}
ByteArrayStream操作字节数组的流
ByteArrayInputStream和ByteArrayOutputStream
/*
ByteArrayStream:用于操作字节数组的流对象
ByteArrayInputStream:在构造时,需要接受数据源,而且数据源是以个字节数组
ByteArrayoutputStream:在构造时,不用定义数据目的,因为该对象中内部封装了可变长度的字节数组,就是数据的目的地
因为这两个流对象都操作的数组,并没有使用系统资源,所以不需要进行close关闭
流操作规律讲解时:
原设备:
键盘 System.in 硬盘 FileStream 内存 ArrayStream
目标设备:
控制台 System.out 硬盘FileStream 内存 ArrayStream
*/
import java.io.*;
class ByteArrayStream
{
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());
}
}
CharArrayStream操作字符数组的流
CharArrayReader和CharArrayWrite
StringStream操作字符串的流
StringReader和StringWriter
字符编码:
/*
转换流的字符编码
*/
import java.io.*;
class EncodeStream
{
public static void main(String[] args)throws IOException
{
//writeFile();
readFile();
}
public static void writeFile()throws IOException
{
//使用指定编码表往文件中写入数据,使用转换流
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf.txt"),"utf-8");
osw.write("你好");
osw.close();
}
public static void readFile()throws IOException
{
//读取时应该指定与写入时同一个编码表,否则会出现不是想要的结果
InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"),"gbk");//(new FileInputStream("utf.txt"),"utf-8")
char[] ch = new char[10];
int x = isr.read(ch);
String str = new String(ch,0,x);
System.out.println(str);
isr.close();
}
}
/*
编码:字符串变字节数组
解码:字节数组变字符串
String-->byte[]; str.getbytes(charsetName);
byte[]-->String; new String(byte[],charsetName);
tomCat服务器就是默认的iso8859-1码表,在向它发送gbk编码时,要在服务端先编码一次在解码一次
注意:如果使用的是gbk编码,用的是utf-8进行解码,这时就不能将utf-8解码数据进行utf-8编码,因为这样获取
不到原先的编码,原因是gbk和utf-8都支持中文,一个是2字节一个是3字节
*/
import java.util.*;
class EncodeDemo
{
public static void main(String[] args) throws Exception
{
String str = "你好";
byte[] by1 = str.getBytes("gbk");
System.out.println(Arrays.toString(by1));
String s1 = new String(by1,"iso8859-1");//当解码误使用了iso8859-1,会得带一个错误的结果
System.out.println(s1);
byte[] by2 = s1.getBytes("iso8859-1");//这时可以对这个字符串在进行一次iso8859-1编码获取原先的编码
System.out.println(Arrays.toString(by2));
String s2 = new String(by2,"gbk");//将获取到的编码再用gbk进行解码
System.out.println(s2);
}
}
/*
有5个学生,每个学生有三门课的成绩,从键盘输入一下数据(姓名加三门课成绩),
输入的格式:如:zhangsan,30,40,50计算出总成绩,并把学生的信息和计算出来的
总成绩由高到低存放在磁盘文件“stud.txt”中
思路:1、创建一个学生类,描述学生信息,让学生类具备比较性或定义比较器进行排序
2、读取录入信息,使用切割方法对录入信息按逗号进行切割,再存入一个可以排序的集合TreeSet
3、取出集合元素,存入硬盘目标地址
*/
import java.io.*;
import java.util.*;
class Student //implements Comparable
{
private String name;
private int sum;
private int ch;
private int math;
private int english;
Student(String name,int ch,int math,int english)
{
this.name=name;
this.ch=ch;
this.math=math;
this.english=english;
sum = ch+math+english;
}
/*public int compareTo(Student s)
{
if(this.sum>s.sum)
return 1;zhangsan,30,40,50
if(this.sum==s.sum)
return this.name.compareTo(s.name);
else
return -1;
}*/
public String getName()
{
return name;
}
public int getSum()
{
return sum;
}
public String toString()
{
return name+":"+ch+","+math+","+english;
}
}
class Com implements Comparator//自定义比较器,优先按总分排序,总分一样按年龄自然顺序排
{
public int compare(Student s1,Student s2)
{
if(s1.getSum()>s2.getSum())
return 1;
if(s1.getSum()==s2.getSum())
return s1.getName().compareTo(s2.getName());
else
return -1;
}
}
class WriteInfo
{
public static void method()throws IOException
{
Comparator cp = Collections.reverseOrder(new Com());//反转比较器,实现由大到小排序
TreeSet ts = new TreeSet(cp);//定义TreeSet集合来存储输入的数据,用于数据的排序
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//定义键盘输入
File addr = new File("stud.txt");//将目标地址封装为一个文件对象
if(! addr.exists())
addr.createNewFile();
PrintWriter pw = new PrintWriter(addr);
String line = null;
while((line=br.readLine())!=null)
{
if(line.equals("end"))
break;
String[] str = line.split(",");//将键盘输入的数据用逗号进行切割,再存储到集合
ts.add(new Student(str[0],Integer.parseInt(str[1]),Integer.parseInt(str[2]),Integer.parseInt(str[3])));
}
//遍历排好序的集合,将集合数据取出使用字符打印流将数据打印到目的地
Iterator it = ts.iterator();
while(it.hasNext())
{
Student stu = it.next();
//System.out.println(stu.toString());
pw.print(stu.toString()+"\t");
pw.println(stu.getSum()+"");
}
br.close();
pw.close();
}
}
class Test
{
public static void main(String[] args) throws IOException
{
WriteInfo.method();
}
}