0. 字節流與二進制文件
我的代碼
public class Main {
public static void main(String[] args)
{
String fileName="d:\\testStream\\0\\student.data";
try(DataOutputStream dos=new DataOutputStream(new FileOutputStream(fileName)))
{
Student stu1=new Student(1,"zhang",13,80);
dos.writeInt(stu1.getId());
dos.writeUTF(stu1.getName());
dos.writeInt(stu1.getAge());
dos.writeDouble(stu1.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)))
{
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 (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
我的總結
一、 使用DataOutputStream與FileOutputStream將Student對象寫入二進制文件student.data
- 二進制文件與文本文件的區別
- 二進制文件可以存儲int/double/char..等基本數據類型,文本文件只能存儲char型變量。因此文本文件在讀取或存儲過程中常需要用到類型轉換(類似parseInt)
2.try...catch...finally注意事項
- catch多個異常時要注意異常寫的先后順序,總體來說越大的(父類)異常要放越后面。可以直接使用eclipse的提示功能直接自己生成異常,方便又不會出錯。
3.使用try..with...resouces關閉資源
- 是jdk8新的語法,可以直接在try(........)的括號中定義最后要關閉的資源,在運行結束后會自動關閉,不需要傳統地在finally中關閉資源。用法詳見上面代碼塊。
1. 字符流與文本文件
我的代碼
任務1
String fileName="d:\\testStream\\1\\Students.txt";
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[] msg=line.split("\\s+");
int id=Integer.parseInt(msg[0]);
String name=msg[1];
int age=Integer.parseInt(msg[2]);
double grade=Double.parseDouble(msg[3]);
Student stu=new Student(id,name,age,grade);
studentList.add(stu);
}
}
catch (FileNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(studentList);
任務2
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[] msg=line.split("\\s+");
int id=Integer.parseInt(msg[0]);
String name=msg[1];
int age=Integer.parseInt(msg[2]);
double grade=Double.parseDouble(msg[3]);
Student stu=new Student(id,name,age,grade);
studentList.add(stu);
}
}
catch (FileNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return studentList;
}
任務3
String fileName="d:\\testStream\\1\\Students.txt";
try(
FileOutputStream fos=new FileOutputStream(fileName,true);
OutputStreamWriter osw=new OutputStreamWriter(fos,"UTF-8");
PrintWriter pw=new PrintWriter(osw))
{
pw.println();
pw.print("4 一一 13 80");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
任務4
String fileName1="d:\\testStream\\1\\Students.dat";
try(
FileOutputStream fos=new FileOutputStream(fileName1);
ObjectOutputStream oos=new ObjectOutputStream(fos))
{
Student ts=new Student(5,"asd",14,60);
oos.writeObject(ts);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try(
FileInputStream fis=new FileInputStream(fileName1);
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();
}
我的總結
- 在任務1、2、3中,程序生成的txt文件是指定的UTF-8編碼。后續如果人為地通過系統自帶的文本文檔打開Students.txt並進行保存,該文本會變成UTF-8-BOM編碼。這樣程序再次運行時就會報錯,因為指定的UTF-8跟文件實際上的UTF-8-BOM是不一樣的,這個問題困擾了我一段時間,目前我的解決方法是兩個:不人為保存,或者需要人為保存時用notepad++。
- 任務3中一開始PrintWriter會直接覆蓋原文件,通過查閱資料,在構造FileOutputStream時多傳一個true就可以了。
- 任務4中,一開始是讓對象流寫在txt中,后面發現會發生亂碼。通過查閱資料知道writeObject()的作用是讓實例以文件的形式保存在磁盤上,而這個文件是用二進制的形式寫的,所以就讓對象流的處理文件是bat格式,就沒錯了。
2.緩沖流
我的代碼
public class Main2 {
public static void main(String[] args) {
String fileName="d:\\testStream\\2\\test.txt";
try (PrintWriter pw = new PrintWriter(fileName);)
{
Random random=new Random();
random.setSeed(100);
double sum=0,aver;
for (int i = 0; i < 1000_0000; i++) {
int r=random.nextInt(10);
sum+=r;
pw.println(r);
}
aver=sum/1000_0000;
System.out.format("%.5f", aver);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
JUNIT測試部分
import static org.junit.jupiter.api.Assertions.*;
import java.io.*;
import java.util.*;
import org.junit.jupiter.api.Test;
class testBufferedReader {
String fileName="d:\\testStream\\2\\test.txt";
@Test
void testScanner() {
try ( FileInputStream fis = new FileInputStream(fileName);
Scanner sc=new Scanner(fis))
{
while(sc.hasNextInt())
{
sc.nextInt();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}finally
{
System.out.println("sc end");
}
}
@Test
void testBufferedReader() {
try ( FileReader fr = new FileReader(fileName);
BufferedReader br=new BufferedReader(fr))
{
String line=null;
while((line=br.readLine())!=null)
{
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}finally
{
System.out.println("br end");
}
}
}
我的總結
- 生成隨機數平時用的少,每次需要用時都得先找點資料,要盡量記住常見的用法。
- 在將隨機數寫入文件時,如果用的是print而不是println,文本大小會是println的三分一(1000_0000字節和3000_0000字節),因為一個回車2字節,沒有寫回車的話junit跑出來的結果Scanner和BufferedReader的時間是差不多的,而寫了回車時間差距就很大。
- JUNIT中要測試的方法前要加上@Test
3.字節流之對象流
我的代碼
public static void writeStudent(List<Student> stuList)
{
String fileName="d:\\testStream\\3\\Students.dat";
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;
}
我的總結
- 使用對象流時,寫入的是一個對象,而不是多個對象。在這里不用像用BufferedReader時一行一個Student對象地讀取,而是直接讀出一個集合或數組
5.文件操作
我的代碼
遞歸
public class Main5 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Path dir=Paths.get("D:\\", "testStream","5");
findFile(dir,"c.txt");
}
public static void findFile(Path dir,String fileName)
{
File file=dir.toFile();
File[] files=file.listFiles();
for(File now:files)
{
if(now.isFile())
{
if(now.getName().equals(fileName))
{
System.out.println(now.getAbsolutePath());
return;
}
}
else if(now.isDirectory())
{
findFile(now.toPath(),fileName);
}
}
}
}
隊列
我的總結
- File類和Path類可以互相轉換,Path是File的升級。
- Paths類可以直接獲得Path對象,不需要new Path。
6.正則表達式
我的代碼
任務1
public class Main6 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
Pattern pattern=Pattern.compile("^[+-]?[0-9]+(\\.\\d+)?");
Matcher matcher=null;
while(sc.hasNext())
{
String str=sc.next();
matcher=pattern.matcher(str);
System.out.println(matcher.matches());
}
sc.close();
}
}
任務2-匹配數字字符串
package javalearning;
import java.io.*;
import java.net.*;
import java.util.regex.*;
/**
* This program displays all URLs in a web page by matching a regular expression that describes the
* <a href=...> HTML tag. Start the program as <br>
* java HrefMatch URL
* @version 1.01 2004-06-04
* @author Cay Horstmann
*/
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="D:\\testStream\\6\\集美大學-計算機工程學院.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();
}
}
}
任務2-匹配圖片字符串(僅展示部分,其余同數字字符串匹配)
String patternImgString = "img\\s[a-zA-Z]+=\".*.(gif|png|jpg|jpeg)\"";
Pattern pattern = Pattern.compile(patternImgString, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(input);
我的總結
- 要熟練匹配字符串平時就要多寫正則表達式,匹配圖片字符串的patternImgString寫了一段時間,最后還是沒有做到完美的匹配(特殊情況會匹配不准確)