0. 字节流与二进制文件
任务1:使用DataOutputStream与FileOutputStream将Student对象写入二进制文件student.data
我的代码
public class Main {
public static void main(String[] args)
{
String fileName="e://student.data";
int length=3;
Student[] students=new Student[length];
students[0]=new Student(1,"张三",19,65);
students[1]=new Student(2,"李四",19,75);
students[2]=new Student(3,"王五",20,85);
Student stu1=new Student();
try(DataOutputStream dos=new DataOutputStream(new FileOutputStream(fileName)))
{
for (int i = 0; i < length; i++) {
dos.writeInt(students[i].getId());
dos.writeUTF(students[i].getName());
dos.writeInt(students[i].getAge());
dos.writeDouble(students[i].getGrade());
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try(DataInputStream dis=new DataInputStream(new FileInputStream(fileName)))
{
while(true) {
int id=dis.readInt();
String name=dis.readUTF();
int age=dis.readInt();
double grade=dis.readDouble();
Student stu=new Student(id,name,age,grade);
System.out.println(stu);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch(EOFException e) {
//已经从流中读完
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
我的总结
Q1: 二进制文件与文本文件的区别
A1: 这两者只是在编码层次上有差异。文本文件编码基于字符定长,译码容易些;二进制文件编码是变长的,所以它灵活,存储利用率要高些,译码难一些
Q2: try...catch...finally注意事项
A2: 捕获多个异常时,如有多个catch块并有继承关系的情况下必须先写子类后写父类(即先捕获小异常再捕获大异常),若写反在编译时就会报错使用。以及执行顺序,先执行try如果未发生异常,继续执行最后执行finally,否者跳过try执行catch最后执行finally.
Q3: try..with...resouces关闭资源
A3: 在Java7中增强了try语句的功能,它允许在try关键字后紧跟一对圆括号,圆括号可以声明、初始化一个或多个资源,此处的资源指的是那些必须在程序结束时显示关闭的资源,try语句在该语句结束时自动关闭这些资源。这些资源实现类必须实现AutoCloseable或Closeable接口,实现这两个接口就必须实现close()方法。
。
任务2:使用DataInputStream与FileInputStream从student.data中读取学生信息并组装成对象
我的代码
try(DataInputStream dis=new DataInputStream(new FileInputStream(fileName)))
{
while(true) {
int id=dis.readInt();
String name=dis.readUTF();
int age=dis.readInt();
double grade=dis.readDouble();
Student stu=new Student(id,name,age,grade);
System.out.println(stu);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch(EOFException e) {
//已经从流中读完
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
1. 字符流与文本文件:使用 PrintWriter(写),BufferedReader(读)
任务
1. 使用BufferedReader从编码为UTF-8的文本文件中读出学生信息,并组装成对象然后输出。
• 中文乱码问题(FileReader使用系统默认编码方式读取文件,会产生乱码,可使用InputStreamReader解决)
• String的split方法使用\s+可以使用多个空格作为分隔符。
• 进阶:修改Students.txt文件,在正确的数据行中间增加一些错误行(如,每行只有3个数据,或者应该是数字的地方放入其他字符),修改自己的程序,让起可以处理出错的行(报错但可以继续运 行)。
2. 编写public static ListreadStudents(String fileName);从fileName指定的文本文件中读取所有学生,并将其放入到一个List中
3. 使用PrintWriter将Student对象写入文本文件,基础代码见后。注意:缓冲区问题。
任务123我的代码
package iostream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
public class PrintRead {
public static void main(String[] args) {
String fileName = "e:/Students.txt";
String inFileName = "e:/inStudents.txt";
System.out.println(PrintRead.readStudents(fileName));
try (PrintWriter pw = new PrintWriter(inFileName)) {
pw.print("张三 ");
pw.print(" 201821123333");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static List<Student> readStudents(String fileName) {
List<Student> studentList = new ArrayList<>();
try (FileInputStream fis = new FileInputStream(fileName);
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
BufferedReader br = new BufferedReader(isr);) {
String line = null;
while ((line = br.readLine()) != null) {
String[] student = line.split("\s+");// split方法\s+多个空格作为分隔符
int id = Integer.parseInt(student[0]);
String name = student[1];
int age = Integer.parseInt(student[2]);
double grade = Double.parseDouble(student[3]);
Student stu = new Student(id, name, age, grade);
studentList.add(stu);
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return studentList;
}
}
任务4:使用ObjectInputStream/ObjectOutputStream读写学生对象。
我的代码
try(
FileOutputStream fos=new FileOutputStream(fileName);
ObjectOutputStream oos=new ObjectOutputStream(fos)
)
{
Student ts=new Student(1,"张三",19,65);
oos.writeObject(ts);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try(
FileInputStream fis=new FileInputStream(fileName);
ObjectInputStream ois=new ObjectInputStream(fis))
{
Student newStudent =(Student)ois.readObject();
System.out.println(newStudent);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
我的总结
Q1:中文乱码问题
A1:FileReader使用系统默认编码方式读取文件,会产生乱码,可使用InputStreamReader解决,在创建时可以设置编码格式比如GBK,UTF-8
Q2:写入文件后,打开为空白文件
A2:文件写入存在缓冲区,先将数据写入缓冲区,效率高,但是如果没有强制将缓冲区内容写入,或者缓冲区未满,或者正常关闭流,并不会真正写入文件,可以使用writer.flush();writer.close()写入文件
2. 缓冲流(结合使用JUint进行测试)
任务:使用PrintWriter往文件里写入1千万行随机整数,范围在[0,10]。随机数种子设置为100.
然后从文件将每行读取出来转换成整数后相加。然后依次输出“个数 和 平均值(保留5位小数)”。
我的代码
package iostream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
import java.util.Scanner;
public class BufferedScanner {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) {
String FILENAME = "e:\test.txt";
//write using PrintWriter
try (PrintWriter pw = new PrintWriter(FILENAME)){
Random random=new Random(100);
for (int i = 0; i < 1000_0000; i++) {
int r=random.nextInt(11);
pw.println(r);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
System.out.println("write using PrintWriter done");
}
}
class Test {
String FILENAME = "e:\test.txt";
@org.junit.jupiter.api.Test
void testBuffered() {
//read using BufferedReader
int sum=0;
int count=0;
try (BufferedReader br = new BufferedReader(new FileReader(new File(FILENAME)))){
String str;
int r;
while((str=br.readLine())!=null){
r=Integer.parseInt(str);
sum+=r;
count++;
};
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.format("%d %d %.5f", count,sum,1.0*sum/count);
System.out.println("read using BufferedReader done");
}
@org.junit.jupiter.api.Test
void testScanner() {
//read using Scanner
int sum=0;
int count=0;
int r;
try (Scanner scanner=new Scanner(new File(FILENAME))){
String str;
while(scanner.hasNextLine()){
str=scanner.nextLine();
r=Integer.parseInt(str);
sum+=r;
count++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
System.out.format("%d %d %.5f", count,sum,1.0*sum/count);
System.out.println("read using Scanner done");
}
}
我的总结
Q1:使用junit对比BufferedReader与Scanner读文件的效率
A1:显而易见用BufferedReader更快,因为BufferedReader采用缓存方式可以有效减少I/O操作次数,进而节省时间
Q2:Scanner的hasNextXXX方法应与相对应的nextXXX方法配合使用,否则容易出错。
Q3:为什么读取出文件后数据量从1000_0000减少的一半变成了500_0000。
A3:因为在while循环中如果采用br.readLine()!=null,文件会指向下一位,如果这时候再在循环直调用readLine,会跳行读取所以减少一半,应该while中写成(str=br.readLine())!=null
3. 字节流之对象流
任务:结合使用ObjectOutputStream、ObjectInputStream与FileInputStream、FileOuputStream实现对Student对象的读写。
编写如下两个方法:
• public static void writeStudent(List stuList)
• public static List readStudents(String fileName)
我的代码
public class PrintRead {
public static void main(String[] args) {
String fileName = "e:/Students.txt";
List<Student> stuList=new ArrayList<>();
stuList.add(new Student(1,"张三",19,65));
stuList.add(new Student(2,"李四",19,75));
stuList.add(new Student(3,"王五",20,85));
PrintRead.writeStudent(stuList);
System.out.println(PrintRead.readStudents(fileName));
}
public static void writeStudent(List<Student> stuList) {
String fileName = "e:/Students.txt";
try (FileOutputStream fos = new FileOutputStream(fileName);
ObjectOutputStream ois = new ObjectOutputStream(fos)) {
ois.writeObject(stuList);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
public static List<Student> readStudents(String fileName) {
List<Student> stuList = new ArrayList<>();
try (FileInputStream fis = new FileInputStream(fileName); ObjectInputStream ois = new ObjectInputStream(fis)) {
stuList = (List<Student>) ois.readObject();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return stuList;
}
}
我的总结
Q1:java.io.NotSerializableException: iostream.Student出现异常
A1:要将对象写入文件,必须实现序列化接口,对象---->流数据 序列化流 (ObjectOutputStream)
• (1)必须序列化之后才可以反序列化
• (2)自定义类要实现序列化功能,必须实现接口Serializable(标记接口),如果没有实现就会报这个错误NotSerializableException。
5. 文件操作
任务:编写一个程序,可以根据指定目录和文件名,搜索该目录及子目录下的所有文件,如果没有找到指定文件名,则显示无匹配,否则将所有找到的文件名与文件夹名显示出来。
1. 编写public static void findFile(Path dir,String fileName)方法.
以dir指定的路径为根目录,在其目录与子目录下查找所有和filename相同的文件名,一旦找到就马上输出到控制台。
我的代码
public class FindDirectories {
public static void main(String[] args) {
// if no arguments provided, start at the parent directory
String fileName = "test.txt";
if (args.length == 0)
args = new String[] { "E:\算法程序设计" };
try {
File pathName = new File(args[0]);
String[] fileNames = pathName.list();
// enumerate all files in the directory
for (int i = 0; i < fileNames.length; i++) {
File f = new File(pathName.getPath(), fileNames[i]);
if (f.isFile()) {
if(f.getName().equals(fileName))
{
System.out.println(f.getAbsolutePath());
flag=true;
}
}
// if the file is again a directory, call the main method recursively
else if (f.isDirectory()) {
if (f.getName().equals(fileName))
{
System.out.println(f.getCanonicalPath());
flag=true;
}
main(new String[] { f.getPath() });//递归
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
我的总结
实现方法主要时通过递归,通过if语句判断当前文件是单个文件或者存在子文件,然后如果存在子文件则递归再次调用,在其子目录下查找所有和filename相同的文件名,一旦找到就马上输出到控制台。
6. 正则表达式
1. 如何判断一个给定的字符串是否是10进制数字格式?尝试编程进行验证。
2. 修改HrefMatch.java
• 尝试匹配网页中的数字字符串
• 尝试匹配网页中的图片字符串
我的代码
public class HrefMatch
{
public static void main(String[] args)
{
try
{
// get URL string from command line or use default
/* String urlString;
if (args.length > 0) urlString = args[0];
else urlString = "http://java.sun.com";*/
String fileName="e:\集美大学-计算机工程学院.htm";
// open reader for URL
//InputStreamReader in = new InputStreamReader(new URL(urlString).openStream());
InputStreamReader in = new InputStreamReader(new FileInputStream(fileName));
// read contents into string builder
StringBuilder input = new StringBuilder();
int ch;
while ((ch = in.read()) != -1)
input.append((char) ch);
String patternString = "[+-]?[0-9]+(\.\d+)?";
Pattern pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(input);
while (matcher.find())
{
int start = matcher.start();
int end = matcher.end();
String match = input.substring(start, end);
System.out.println(match);
}
}
catch (IOException e)
{
e.printStackTrace();
}
catch (PatternSyntaxException e)
{
e.printStackTrace();
}
}
}