Java學習筆記10--位元組流 ;字元流 ;序列流 ;物件的輸入輸出流;Properties(配置檔案類);列印流;編碼
∆ 位元組流、字元流
∆ SequenceInputStream(序列流)
序列流,對多個流進行合併。
SequenceInputStream 表示其他輸入流的邏輯串聯。它從輸入流的有序集合開始,並從第一個輸入流開始讀取,直到到達檔案末尾,接著從第二個輸入流讀取,依次類推,直到到達包含的最後一個輸入流的檔案末尾為止。
需求:的內容合併
public class Demo1 {
public static void main(String[] args) throws IOException {
merge3();
}
//把三個檔案合併成一個檔案
public static void merge3() throws IOException{
//找到目標檔案
File file1 = new File("F:\\a.txt");
File file2 = new File("F:\\b.txt");
File file3 = new File("F:\\c.txt");
File file4 = new File("F:\\d.txt");
//建立對應 的輸入輸出流物件
FileOutputStream fileOutputStream = new FileOutputStream(file4);
FileInputStream fileInputStream1 = new FileInputStream(file1);
FileInputStream fileInputStream2 = new FileInputStream(file2);
FileInputStream fileInputStream3 = new FileInputStream(file3);
//建立序列流物件
Vector<FileInputStream> vector = new Vector<FileInputStream>();
vector.add(fileInputStream1);
vector.add(fileInputStream2);
vector.add(fileInputStream3);
Enumeration<FileInputStream> e = vector.elements();
SequenceInputStream sequenceInputStream = new SequenceInputStream(e);
//讀取檔案資料
byte[] buf = new byte[1024];
int length = 0;
while((length = sequenceInputStream.read(buf))!=-1){
fileOutputStream.write(buf,0,length);
}
//關閉資源
sequenceInputStream.close();
fileOutputStream.close();
}
// 使用SequenceInputStream合併檔案。
public static void merge2() throws IOException{
//找到目標檔案
File inFile1 = new File("F:\\a.txt");
File inFile2 = new File("F:\\b.txt");
File outFile = new File("F:\\c.txt");
//建立資料的輸入輸出通道
FileOutputStream fileOutputStream = new FileOutputStream(outFile);
FileInputStream fileInputStream1 = new FileInputStream(inFile1);
FileInputStream fileInputStream2 = new FileInputStream(inFile2);
//建立序列流物件
SequenceInputStream inputStream = new SequenceInputStream(fileInputStream1,fileInputStream2);
byte[] buf = new byte[1024];
int length = 0 ;
while((length = inputStream.read(buf))!=-1){
fileOutputStream.write(buf,0,length);
}
//關閉資源
inputStream.close();
fileOutputStream.close();
}
//需求:把a.txt與b.txt 檔案的內容合併。
public static void merge1() throws IOException{
//找到目標檔案
File inFile1 = new File("F:\\a.txt");
File inFile2 = new File("F:\\b.txt");
File outFile = new File("F:\\c.txt");
//建立資料的輸入輸出通道
FileOutputStream fileOutputStream = new FileOutputStream(outFile);
FileInputStream fileInputStream1 = new FileInputStream(inFile1);
FileInputStream fileInputStream2 = new FileInputStream(inFile2);
//把輸入流儲存到集合中,然後再從集合中讀取
ArrayList<FileInputStream> list = new ArrayList<FileInputStream>();
list.add(fileInputStream1);
list.add(fileInputStream2);
//準備一個緩衝陣列
byte[] buf = new byte[1024];
int length = 0 ;
for(int i = 0 ; i< list.size() ; i++){
FileInputStream fileInputStream = list.get(i);
while((length = fileInputStream.read(buf))!=-1){
fileOutputStream.write(buf,0,length);
}
//關閉資源
fileInputStream.close();
}
fileOutputStream.close();
}
}
舉例Demo: 需求: 把一首mp3先切割成n份,然後再把這些檔案合併起來。
public class Demo2 {
public static void main(String[] args) throws IOException {
// cutFile();
mergeFlile();
}
//合併
public static void mergeFlile() throws IOException{
//找到目標檔案
File dir = new File("F:\\music");
//通過目標資料夾找到所有的MP3檔案,然後把所有的MP3檔案新增到vector中。
Vector<FileInputStream> vector = new Vector<FileInputStream>();
File[] files = dir.listFiles();
for(File file : files){
if(file.getName().endsWith(".mp3")){
vector.add(new FileInputStream(file));
}
}
//通過Vector獲取迭代器
Enumeration<FileInputStream> e = vector.elements();
//建立序列流
SequenceInputStream inputStream = new SequenceInputStream(e);
//建立檔案的輸出通道
FileOutputStream fileOutputStream = new FileOutputStream("F:\\合併.mp3");
//建立緩衝陣列讀取檔案
byte[] buf = new byte[1024];
int length = 0 ;
while((length = inputStream.read(buf))!=-1){
fileOutputStream.write(buf,0,length);
}
//關閉資源
fileOutputStream.close();
inputStream.close();
}
//切割MP3
public static void cutFile() throws IOException{
File file = new File("F:\\美女\\1.mp3");
//目標資料夾
File dir = new File("F:\\music");
//建立資料的輸入通道
FileInputStream fileInputStream = new FileInputStream(file);
//建立緩衝陣列讀取
byte[] buf = new byte[1024*1024];
int length = 0;
for(int i = 0 ; (length = fileInputStream.read(buf))!=-1 ; i++){
FileOutputStream fileOutputStream = new FileOutputStream(new File(dir,"part"+i+".mp3"));
fileOutputStream.write(buf,0,length);
fileOutputStream.close();
}
//關閉資源
fileInputStream.close();
}
}
∆ 物件的輸入輸出流
當建立物件時,程式執行時它就會存在,但是程式停止時,物件也就消失了.但是如果希望物件在程式不執行的情況下仍能存在並儲存其資訊,將會非常有用,物件將被重建並且擁有與程式上次執行時擁有的資訊相同。可以使用物件的序列化。
物件的序列化: 將記憶體中的物件直接寫入到檔案裝置中
物件的反序列化: 將檔案裝置中持久化的資料轉換為記憶體物件
基本的序列化由兩個方法產生:一個方法用於序列化物件並將它們寫入一個流,另一個方法用於讀取流並反序列化物件。
ObjectOutput
writeObject(Object obj)
將物件寫入底層儲存或流。
ObjectInput
readObject()
讀取並返回物件。
ObjectOutputStream的使用步驟:
物件輸入輸出流要注意的細節:
- 如果物件需要被寫出到檔案上,那麼物件所屬的類必須要實現Serializable介面。 Serializable介面沒有任何的方法,是一個標識介面而已。
- 物件的反序列化建立物件的時候並不會呼叫到構造方法的、
- serialVersionUID 是用於記錄class檔案的版本資訊的,serialVersionUID這個數字是通過一個類的類名、成員、包名、工程名算出的一個數字。
- 使用ObjectInputStream反序列化的時候,ObjeectInputStream會先讀取檔案中的serialVersionUID,然後與本地的class檔案的serialVersionUID進行對比,如果這兩個id不一致,那麼反序列化就失敗了。
- 如果序列化與反序列化的時候可能會修改類的成員,那麼最好一開始就給這個類指定一個serialVersionUID,如果一類已經指定的serialVersionUID,然後在序列化與反序列化的時候,jvm都不會再自己算這個 class的serialVersionUID了。
- 如果一個物件某個資料不想被序列化到硬碟上,可以使用關鍵字transient修飾。
- 如果一個類維護了另外一個類的引用,那麼另外一個類也需要實現Serializable介面。
程式碼舉例:
class Address implements Serializable{
String country;
String city;
public Address(String country,String city){
this.country = country;
this.city = city;
}
}
class User implements Serializable{
private static final long serialVersionUID = 1L;
String userName ;
String password;
transient int age; // transient 透明
Address address ;
public User(String userName , String passwrod) {
this.userName = userName;
this.password = passwrod;
}
public User(String userName , String passwrod,int age,Address address) {
this.userName = userName;
this.password = passwrod;
this.age = age;
this.address = address;
}
@Override
public String toString() {
return "使用者名稱:"+this.userName+ " 密碼:"+ this.password+" 年齡:"+this.age+" 地址:"+this.address.city;
}
}
public class Demo3 {
public static void main(String[] args) throws IOException, Exception {
writeObj();
// readObj();
}
//把檔案中的物件資訊讀取出來-------->物件的反序列化
public static void readObj() throws IOException, ClassNotFoundException{
//找到目標檔案
File file = new File("F:\\obj.txt");
//建立資料的輸入通道
FileInputStream fileInputStream = new FileInputStream(file);
//建立物件的輸入流物件
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
//讀取物件資訊
User user = (User) objectInputStream.readObject(); //建立物件肯定要依賴物件所屬 的class檔案。
System.out.println("物件的資訊:"+ user);
}
//定義方法把物件的資訊寫到硬碟上------>物件的序列化。
public static void writeObj() throws IOException{
//把user物件的資訊持久化儲存。
Address address = new Address("中國","廣州");
User user = new User("admin","123",15,address);
//找到目標檔案
File file = new File("F:\\obj.txt");
//建立資料輸出流物件
FileOutputStream fileOutputStream = new FileOutputStream(file);
//建立物件的輸出流物件
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
//把物件寫出
objectOutputStream.writeObject(user);
//關閉資源
objectOutputStream.close();
}
}
∆ Properties(配置檔案類)
主要用於生產配置檔案與讀取配置檔案的資訊。
可以和流相關聯的集合物件Properties.
Map
|--Hashtable
|--Properties
Properties:該集合不需要泛型,因為該集合中的鍵值對都是String型別。
1,存入鍵值對:setProperty(key,value);
2,獲取指定鍵對應的值:value getProperty(key);
3,獲取集合中所有鍵元素:
Enumeration propertyNames();
Properties要注意的細節:
- 如果配置檔案的資訊一旦使用了中文,那麼在使用store方法生成配置檔案的時候只能使用字元流解決,如果使用位元組流生成配置檔案的話,預設使用的是iso8859-1碼錶進行編碼儲存,這時候會出現亂碼。
- 如果Properties中的內容發生了變化,一定要重新使用Properties生成配置檔案,否則配置檔案資訊不會發生變化。
public class Demo4 {
public static void main(String[] args) throws IOException {
creatProperties();
// readProperties();
}
//讀取配置檔案的資訊
public static void readProperties() throws IOException{
//建立Properties物件
Properties properties = new Properties();
//載入配置檔案資訊到Properties中
properties.load(new FileReader("F:\\persons.properties"));
//遍歷
Set<Entry<Object, Object>> entrys = properties.entrySet();
for(Entry<Object, Object> entry :entrys){
System.out.println("鍵:"+ entry.getKey() +" 值:"+ entry.getValue());
}
//修改狗娃的密碼
//把修改後的Properties再生成一個配置檔案
properties.setProperty("狗娃", "007");
properties.store(new FileWriter("F:\\persons.properties"), "hehe");
}
//儲存配置檔案檔案的資訊。
public static void creatProperties() throws IOException{
//建立Properties
Properties properties = new Properties();
properties.setProperty("狗娃", "123");
properties.setProperty("狗剩","234");
properties.setProperty("鐵蛋","345");
// 遍歷Properties
/*Set<Entry<Object, Object>> entrys = properties.entrySet();
for(Entry<Object, Object> entry :entrys){
System.out.println("鍵:"+ entry.getKey() +" 值:"+ entry.getValue());
}*/
//使用Properties生產配置檔案。
//properties.store(new FileOutputStream("F:\\persons.properties"), "haha"); //第一個引數是一個輸出流物件,第二引數是使用一個字串描述這個配置檔案的資訊。
properties.store(new FileWriter("F:\\persons.properties"), "hehe");
}
}
程式碼舉例: 使用properties實現本軟體只能 執行三次,超過了三次之後就提示購買正版,退jvm.
public class Demo5 {
public static void main(String[] args) throws IOException {
File file = new File("F:\\count.properties");
if(!file.exists()){
//如果配置檔案不存在,則建立該配置檔案
file.createNewFile();
}
//建立Properties物件。
Properties properties = new Properties();
//把配置檔案的資訊載入到properties中
properties.load(new FileInputStream(file));
FileOutputStream fileOutputStream = new FileOutputStream(file);
int count = 0; //定義該變數是用於儲存軟體的執行次數的。
//讀取配置檔案的執行次數
String value = properties.getProperty("count");
if(value!=null){
count = Integer.parseInt(value);
}
//判斷使用的次數是否已經達到了三次,
if(count==3){
System.out.println("你已經超出了試用次數,請購買正版軟體!!");
System.exit(0);
}
count++;
System.out.println("你已經使用了本軟體第"+count+"次");
properties.setProperty("count",count+"");
//使用Properties生成一個配置檔案
properties.store(fileOutputStream,"runtime");
}
}
∆ 列印流(printStream)
列印流(printStream) 列印流可以列印任意型別的資料,而且列印資料之前都會先把資料轉換成字串再進行列印。
PrintStream:
是一個位元組列印流,System.out對應的型別就是PrintStream。
它的建構函式可以接收三種資料型別的值。
- 字串路徑。
- File物件。
- OutputStream。
public static void main(String[] args) throws IOException {
PrintStream ps = System.out;
// 普通write方法需要呼叫flush或者close方法才會在控制檯顯示
// ps.write(100);
// ps.close();
// 不換行列印
ps.print(100);
ps.print('a');
ps.print(100.5);
ps.print("世界");
ps.print(new Object());
System.out.println("--------------");
// 換行
ps.println(100);
ps.println('a');
ps.println(100.5);
ps.println("世界");
ps.println(new Object());
// 重定向列印流
PrintStream ps2 = new PrintStream(new File("c:\\a.txt"));
System.setOut(ps2);
// 換行
ps2.println(100);
ps2.println('a');
ps2.println(100.5);
ps2.println("世界");
ps2.println(new Object());
// printf(); 格式化
ps2.printf("%d,%f,%c,%s", 100, 3.14, '中', "世界你好!!!");
ps2.printf("%4s和%8s 打價格戰", "京東", "蘇寧");
} }
程式碼舉例:
class Animal{
String name;
String color;
public Animal(String name,String color){
this.name = name;
this.color = color;
}
@Override
public String toString() {
return "名字:"+this.name+ " 顏色:"+ this.color;
}
}
public class Demo6 {
public static void main(String[] args) throws IOException {
/*FileOutputStream fileOutputStream = new FileOutputStream("F:\\a.txt");
fileOutputStream.write("97".getBytes());
fileOutputStream.close();*/
//列印流可以列印任何型別的資料,而且列印資料之前都會先把資料轉換成字串再進行列印。
File file = new File("F:\\a.txt");
//建立一個列印流
PrintStream printStream = new PrintStream(file);
/*
printStream.println(97);
printStream.println(3.14);
printStream.println('a');
printStream.println(true);
Animal a = new Animal("老鼠", "黑色");
printStream.println(a);
//預設標準的輸出流就是向控制檯輸出的,
System.setOut(printStream); //重新設定了標準的輸出流物件
System.out.println("哈哈,猜猜我在哪裡!!");
*/
//收集異常的日誌資訊。
File logFile = new File("F:\\2015年1月8日.log");
PrintStream logPrintStream = new PrintStream( new FileOutputStream(logFile,true) );
try{
int c = 4/0;
System.out.println("c="+c);
int[] arr = null;
System.out.println(arr.length);
}catch(Exception e){
e.printStackTrace(logPrintStream);
}
}
}
∆ 編碼
∆ 轉換流:
輸入位元組流的轉換流:InputStreamReader 是位元組流通向字元流的橋
InputStreamReader
輸出位元組流的轉換流:
OutputStreamWriter 可以把輸出位元組流轉換成輸出字元流 。
轉換流的作用:
1. 如果目前所 獲取到的是一個位元組流需要轉換字元流使用,這時候就可以使用轉換流。 位元組流----> 字元流
2. 使用轉換流可以指定編碼表進行讀寫檔案。
public class Demo8 {
public static void main(String[] args) throws IOException {
// readTest();
// writeTest();'
// writeTest2();
readTest2();
}
//使用輸入位元組流的轉換流指定碼錶進行讀取檔案資料
public static void readTest2() throws IOException{
File file = new File("F:\\a.txt");
FileInputStream fileInputStream = new FileInputStream(file);
//建立位元組流的轉換流並且指定碼錶進行讀取
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"utf-8");
char[] buf = new char[1024];
int length = 0;
while((length = inputStreamReader.read(buf))!=-1){
System.out.println(new String(buf,0,length));
}
}
//使用輸出位元組流的轉換流指定碼錶寫出資料
public static void writeTest2() throws IOException{
File file = new File("F:\\a.txt");
//建立資料的輸出通道
FileOutputStream fileOutputStream = new FileOutputStream(file);
//把輸出位元組流轉換成字元流並且指定編碼表。
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "utf-8");
outputStreamWriter.write("新中國好啊");
//關閉資源
outputStreamWriter.close();
}
public static void writeTest() throws IOException{
File file = new File("F:\\a.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
//把輸出位元組流轉換成輸出字元流。
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
outputStreamWriter.write("大家好");
outputStreamWriter.close();
}
public static void readTest() throws IOException{
InputStream in = System.in; //獲取了標準的輸入流。
// System.out.println("讀到 的字元:"+ (char)in.read()); //read()一次只能讀取一個位元組。
//需要把位元組流轉換成字元流。
InputStreamReader inputStreamReader = new InputStreamReader(in);
//使用字元流的緩衝類
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line = null;
while((line = bufferedReader.readLine())!=null){
System.out.println("內容:"+ line);
}
}
}