一、File类
1)File类包含了获得一个文件/目录的属性,以及对文件/目录进行改名和删除的方法。但是FIle类不包括读写文件内容的方法
2)在Windows中目录的分割符是反斜杠(\)。但是在java中,反斜杠是一个特殊字符,应该写成\\的形式
斜杠(/)是java的目录分隔符
3).代表当前目录 ..代表当前目录的父目录
4)一些常用的方法
File file = new File("us.txt");//依据相对路径创建File对象,相对当前工作目录
System.out.println(file.exists()); //File对象所代表的文件或者目录,是否存在
System.out.println(file.canRead()); //存在且可读?
System.out.println(file.canWrite());//存在且可写?
System.out.println(file.isDirectory()); //是目录吗?
System.out.println(file.isFile()); //还是文件呢?
System.out.println(file.getAbsolutePath()); //绝对路径是什么
System.out.println(file.getPath()); //创建时是什么样的路径,就返回什么样的
System.out.println(file.getParent()); //父目录是什么
System.out.println(file.getName()); //文件名是什么
//文件的大小,以字节为单位。如果不存在,或者是个目录的话,返回0
System.out.println(file.length());
//返回一个目录对象下的所有File对象,一般要先判断是否是目录
System.out.println(file.listFiles());
System.out.println(file.renameTo(new File("jav.txt"))); //重命名,有bug,还是不要用
System.out.println(file.delete());//删除对象代表的文件或者目录,成功则返回true
5)注意事项
5.1)构建一个File实例,并不会在机器上创建一个文件。不管文件是否存在,都可以创建任意文件名的File实例。可以调用File实例上的exists()方法来判断这个文件是否存在
二、文本文件输入与输出
1)使用PrintWriter类可以用来创建一个文件并向文本文件中写入数据,
格式 PrintWriter output = new PrintWriter(arg1); // arg1可以是File对象,也可以是filename
注意:和new File不同的是,文件不存在的时候,PrintWriter真的会创建文件
1.1)PrintWriter类有各种print、printf、printfln方法向文件中写入数据
例子:
public class Test {
public static void main(String[] args) throws FileNotFoundException {
File file = new File("score.txt");
if(file.exists()){//如果文件存在,我们就不写了,直接退出程序
//当然了,你硬要写也行。。这只是个例子
System.out.println("File already exists");
System.exit(1);
}
//文件不存在,我们就创一个
PrintWriter output = new PrintWriter(file);
output.print("John T Smith");
output.println(90);
output.print("Eric K Jones");
output.println(85);
output.close(); //如果没有这句,数据就不能正确保存在文件中
//但是 close()容易忘啊。没关系,有一种不写的方法
/*try(
PrintWriter output = new PrintWriter(file); //规定,每一个资源的创建和声明必须在同一行
//可以进行多个资源的声明和创建
){
output.print("John T Smith");
output.println(90);
output.print("Eric K Jones");
output.println(85);
}*/
//这个叫 try-with-resourse语法。当运行完了这一块,就会自动关闭文件
}
}
2)使用Scanner从文件中读取数据
格式Scanner input = new Scanner(file);
2.1)Scanner有各种next、nextLine、nextInt等等方法,读取数据。。尤其要记得一个hasNext()方法,用来判断是否还有数据要读
2.2)例子:
public class Test {
public static void main(String[] args) throws FileNotFoundException {
File file = new File("score.txt");
Scanner input = new Scanner(file);
while(input.hasNext()){
String firstName = input.next();
String mi = input.next();
String lastName = input.next();
int score = input.nextInt();
System.out.println(
firstName + " " + mi + " " + lastName + " " + score);
}
input.close(); //没必要关闭输入文件,但这样做能释放被文件占用的内存
}
}
默认情况下的分隔符是空格,可以使用useDelimiter(String regex)方法设置新的分隔符
例子:
Scanner input = new Scanner(System.in);
input.useDelimiter(",");
String name = input.next();
int score = input.nextInt();
String sex = input.next();
System.out.println(name + " " + score + " " + sex);
输入:张三,88,女,
输出结果:张三 88 女
2.4)标记读取方法(除了nextLine()不是),不能读取标记后面的分隔符
例子1:
Scanner input = new Scanner(System.in);
// 输入: 34 567
int value = input.nextInt();
String s = input.nextLine();
//输出结果
System.out.println("value is " + value); //value is 34
System.out.println("the length of s is " + s.length()); // 4.
//原因是nextInt()不读后面分隔符空格(回车、Tab),会在分隔符处停止
//以nextline()的角度来看,它读取分隔符回车,在回车之后结束
//但是空格在它前面,何况也不是它的分隔符,所以被读取到
//nextline()会读取分隔符回车,但是它只返回回车以前的字符串
2.5)nextLine()会读取分隔符回车,但是它只返回回车以前的字符串
//验证,nextLine()会读取分隔符回车,但是它只返回回车以前的字符串
Scanner input = new Scanner(System.in);
/* 输入: 34(回车)
567 //好吧,其实你567来不及输入,结果就已经出来了
*/
int value = input.nextInt();
String s = input.nextLine();
//输出结果
System.out.println("value is " + value); //value is 34
System.out.println("the length of s is " + s.length()); // 0
//原因依旧是如此,nextInt()读完34之后,停在回车这个字符上
//nextline()是读取一行,而这行只剩下回车,于是只读到回车
//但是它返回的又是回车之前的字符串,也就是没有
//验证,next()、nextInt()等方法从有效字符读起
Scanner input = new Scanner(System.in);
/* 输入: (空格)(Tab键)34(空格)50.2(回车)(空格)zhangsan(回车)
*/
int intValue = input.nextInt();
double doubleValue = input.nextDouble();
String s = input.next();
//输出结果
System.out.println("intValue is " + intValue); //intValue is 34
System.out.println("doubleValue is " + doubleValue); //doubleValue is 50.2
System.out.println("the length of s is " + s.length());// 8
System.out.println("s is " + s);//s is zhangsan
如果知道Web上数据的URL地址,那么就可以从Web上读取数据
格式:URL url = new URL("http://www.google.com/index.html")
前缀htttp://是必须的,不然就会出错
例子:
// 输入: http://cs.armstrong.edu/liang/data/Lincoln.txt
System.out.print("Enter a URL: ");
String URLString = new Scanner(System.in).next();
try {
URL url = new URL(URLString);
int count = 0;
Scanner input = new Scanner(url.openStream());
while(input.hasNext()){
String line = input.nextLine();
count += line.length();
}
System.out.println("The file size is " + count + " characters");
} catch (MalformedURLException e) {
System.out.println("Invalid URL");
} catch (IOException e) {
System.out.println("I/O Erros: no such file");
}
四、二进制I/O
1)文本文件,是由字符序列构成的(虽然不太准确,但是便于理解)。比如199在文本文件中是以三个字符序列‘1’,‘9’,‘9’来存储的
2)二进制文件,是由位(bit)序列构成的。比如199在二进制文件中,就是等价的十六进制数C7。
3)流:通过一定的传播路径从源传递到目的地的字节序列。流是数据传播的管道。
4)写入一个字符时,java虚拟机会将统一码(Unicode码)转换化为文本文件指定的编码;而在读取字符时,将文件中指定的编码转化为统一码
例如,假设使用文本I/O将字符串“199”写入文件,那么每个字符(‘1’,‘9’,‘9)都会写入到文件中,由于Windows系统中文本文件的默认编码是ASCII,所以是0X31 0X39 0X39,也就是说需要3*8 = 24位
而因为二进制文件都是统一码,所以不必转换。。多少位足够,就用多少位。199,等价十六进制数C7,用8位就够了
五、二进制I/O输入与输出
1)FileInputStream与FileOutputStream
缺点:只能读取或者写入字节byte,或者字节数组。。比如说你写入一个int型,它只给你保留低8位
2)DataInputStream与DataOutputStream
优点:可以读取写入各种数据类型
例子:
public static void main(String[] args) throws IOException{
try(
DataOutputStream output = new DataOutputStream(new FileOutputStream("temp.dat"));
){
output.writeUTF("John"); //以UTF格式写入一个字符串
//output.writeBytes("John"); //将字符串中每个字符统一码的低字节写到输出流。。
//适用于由ASCII码字符构成的字符串
output.writeDouble(85.5);
output.writeUTF("Jim");
output.writeDouble(100);
}
try(
DataInputStream input = new DataInputStream(new FileInputStream("temp.dat"));
){
System.out.println(input.readUTF() + " " + input.readDouble());
System.out.println(input.readUTF() + " " + input.readDouble());
}
}
2.1)注意,UTF-8格式
UTF-8分别使用1字节、2字节、3字节来存储字符。如果字符的编码值小于等于0x7F就将该字符编码为一个字节,如果字符的编码值小于等于0x7FF,就将它编码为两个字符,如果大于0x7FF就编码为3个字节
UTF-8字符起始的几位表明这个字符是存储在一个字节、两个字节还是三个字节中。如果首位是0,那它就是一个字节的字符。如果前三位是110,那它就是两个字节。如果首位是1110,那它就是三个字节。
UTF-8字符的前两个字节用来存储字符串中的字符个数信息
例如: writeUTF("ABCDEF")写入文件的是8个字节(即十六进制简写 00 06 41 42 43 44 45 46)。头两个字节00 06表示字符串中字符的个数。。41 42 43 44 45 46的(二进制展开)前几位都是0,表示它们都是一个字节
writeUTF写入的字符串,必须用readUTF读取,不然得不到想要的结果
3)检测文件的末尾
如果到达InputStream的末尾之后还继续从中读取数据,就会发生EOFException异常。这个异常可以用来检查是否已经到达文件末尾。
例子:
public static void main(String[] args){
try{
try(
DataOutputStream output = new DataOutputStream(new FileOutputStream("test.dat"));
){
output.writeDouble(85.5);
output.writeDouble(105.5);
output.writeDouble(100);
}
try(
DataInputStream input = new DataInputStream(new FileInputStream("test.dat"));
){
while(true){
System.out.println(input.readDouble());
}
}
}
catch (EOFException ex) {
System.out.println("All data were read");
}
catch (IOException e) {
e.printStackTrace();
}
}
4)BufferedInputStream和BufferedOutputStream
优点:减少磁盘读写次数来提高输入输出的速度
缺点:只能读取或者写入字节byte,或者字节数组
4.1)原理:
使用BufferedInputStream时,磁盘上的整块数据一次性地读入到内存中的缓冲区。然后从缓冲区中将个别数据传递到程序中
使用BufferedOutputStream时,个别数据首先写入到内存中的缓冲区中。当缓冲区已满时,缓冲区中的所有数据一次性地写入到磁盘中
4.2)创建:
BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream("test.dat"));
BufferedInputStream input = new BufferedInputStream(new FileInputStream("test.dat"));
5)BufferedReader和BufferedWriter
5.1)是BufferedInputStream和BufferedOutputStream的进阶版,不再只是读写字节了,但是只能接受字符、字符数组和字符串
5.2)创建:
BufferedWriter output = new BufferedWriter(new FileWriter("test.dat"));
六、对象I/O
1)ObjectInputStream类和ObjectOutputStream
可以读写可序列化对象
包含DataInputStream和DataOutputStream的所有功能
2)例子:
public static void main(String[] args) throws IOException{
try(
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("object.dat"));
){
output.writeUTF("John");
output.writeDouble(85.5);
output.writeObject(new Date());
}
}