Day14基礎(chǔ)不牢地動(dòng)山搖-Java基礎(chǔ)
1、定時(shí)器
推動(dòng)整個(gè)計(jì)算機(jī)硬件的發(fā)展的核心關(guān)鍵性技術(shù)就是時(shí)鐘。所以在企業(yè)開發(fā)中定時(shí)操作往往成為開發(fā)重點(diǎn)。而在JDK本身也支持這種定時(shí)調(diào)度的處理操作,這種操作不會直接使用。還是和多線程有關(guān)。
- 如果想要定時(shí)調(diào)度處理操作,需要兩個(gè)類
- 定時(shí)調(diào)度任務(wù):java.util.TimerTask定時(shí)調(diào)度操作:java.util.Timer
package com.day14.demo;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
class MyTask extends TimerTask{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(new SimpleDateFormat("YYYY-MM-dd HH:mm:ss.SSS").format(new Date()));
}
}
public class TaskDemo {
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new MyTask(), 1000,2000);
}
}
2、UUID類
UUID類是根據(jù)你當(dāng)前的地址還有時(shí)間戳自動(dòng)生成一個(gè)幾乎不會重復(fù)的字符串。
package com.day14.demo;
import java.util.UUID;
public class UUIDDemo {
public static void main(String[] args) {
UUID uuid = UUID.randomUUID();
System.out.println(uuid);
}
}
以后再文件上傳等類似的操作中通過UUID類來進(jìn)行簡單的文件名稱,以防止重名的問題。
3、Base64加密處理
Base64是一種數(shù)據(jù)加密算法,使用整個(gè)算法可以使我們的數(shù)據(jù)進(jìn)行安全處理。如果要想進(jìn)行加密處理可以使用兩個(gè):加密器、解密器。
加密處理
package com.day14.demo;
import java.util.Base64;
public class Base64Demo {
public static void main(String[] args) {
String msg = "123456";
String emsg = Base64.getEncoder().encodeToString(msg.getBytes());
System.out.println("加密:" + emsg);
byte[] decode = Base64.getDecoder().decode(emsg);
System.out.println("解密:" + new String(decode));
}
}
多次加密
package com.day14.demo;
import java.util.Base64;
public class Base64Demo {
public static void main(String[] args) {
String msg = encode("123456");
String emsg = encode(encode(encode(msg)));
System.out.println("加密:" + emsg);
byte[] decode = Base64.getDecoder().decode(emsg);
System.out.println("解密:" + new String(decode));
}
public static String encode(String code){
return Base64.getEncoder().encodeToString(code.getBytes());
}
}
還有一個(gè)做法就是種子樹
package com.day14.demo;
import java.util.Base64;
public class Base64Demo {
public static void main(String[] args) {
String sed = encode("zsr--rsz");
String msg = "123456"+sed;
String emsg = encode(msg);
System.out.println("加密:" + emsg);
byte[] decode = Base64.getDecoder().decode(emsg);
System.out.println("解密:" + new String(decode));
}
public static String encode(String code){
return Base64.getEncoder().encodeToString(code.getBytes());
}
}
必須保證長度,以后的開發(fā)將Base64和MD5一起開發(fā),長度是32位。
4、ThreadLocal類
TheadLocal類不繼承Thread類,也不實(shí)現(xiàn)Runable接口,ThreadLocal類為每一個(gè)線程都維護(hù)了自己獨(dú)有的變量拷貝。每個(gè)線程都擁有自己獨(dú)立的變量。
ThreadLocal采用了“以空間換時(shí)間”的方式:訪問并行化,對象獨(dú)享化。前者僅提供一份變量,讓不同的線程排隊(duì)訪問,而后者為每一個(gè)線程都提供了一份變量,因此可以同時(shí)訪問而互不影響。
ThreadLocal的實(shí)現(xiàn)是這樣的:每個(gè)Thread維護(hù)了一個(gè)ThreadLocalMap映射表,這個(gè)映射表的key是ThreadLocal實(shí)例本身。Value是真正需要存儲的變量。也就是說,ThreadLocal本身并不存儲值,它只是作為一個(gè)key來讓線程從ThreadLocalMap獲取value。注意,ThreadLocalMap是使用ThreadLocal的弱引用作為key的,弱引用的對象在GC時(shí)會被回收。
通過給方法傳遞參數(shù),調(diào)用兩個(gè)線程輸出不同的信息
package com.day14.demo;
class Message{
private String note;
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
};
}
class GetMessage{
public void print(Message msg){
System.out.println(Thread.currentThread().getName() + msg.getNote());
}
}
public class ThreadLocalDemo {
public static void main(String[] args) {
new Thread(()->{
Message message = new Message();
message.setNote("Hello,world!!");
new GetMessage().print(message);
},"用戶A").start();
new Thread(()->{
Message message = new Message();
message.setNote("Hello,world!!zsr");
new GetMessage().print(message);
},"用戶B").start();
}
}
但是我現(xiàn)在的需求是不希望通過傳遞傳輸給GetMessage的print方法,還希望實(shí)現(xiàn)相同的功能。
package com.day14.demo;
class Message{
private String note;
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
};
}
class GetMessage{
public void print(Message msg){
System.out.println(Thread.currentThread().getName() + msg.getNote());
}
}
public class ThreadLocalDemo {
public static void main(String[] args) {
new Thread(()->{
Message message = new Message();
message.setNote("Hello,world!!");
new GetMessage().print(message);
},"用戶A").start();
new Thread(()->{
Message message = new Message();
message.setNote("Hello,world!!zsr");
new GetMessage().print(message);
},"用戶B").start();
}
}
我們發(fā)現(xiàn)兩個(gè)線程的內(nèi)容并沒有同步輸出,所以我們會想到通過ThreadLocal類來解決此數(shù)據(jù)不同步的問題。

public class ThreadLocal<T> extends Object
這個(gè)類里面有幾個(gè)重要的方法:
- 取得數(shù)據(jù):public T get()
- 存放數(shù)據(jù):public void set(T value)
- 刪除數(shù)據(jù):public void remove()
利用ThreadLocal來解決當(dāng)前我問題
package com.day14.demo;
class Message{
private String note;
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
};
}
class GetMessage{
public void print(){
System.out.println(Thread.currentThread().getName() + MyUtil.get().getNote());
}
}
class MyUtil{
private static ThreadLocal<Message> tl = new ThreadLocal<Message>();
public static void set(Message msg){
tl.set(msg);
}
public static Message get(){
return tl.get();
}
}
public class ThreadLocalDemo {
public static void main(String[] args) {
new Thread(()->{
Message msg = new Message();
msg.setNote("Hello,world!!");
MyUtil.set(msg);
new GetMessage().print();
},"用戶A").start();
new Thread(()->{
Message msg = new Message();
msg.setNote("Hello,world!!zsr");
MyUtil.set(msg);
new GetMessage().print();
},"用戶B").start();
}
}
這樣我們就解決了數(shù)據(jù)不同步的問題了。
5、IO—File類
5.1 基本操作
如果要想學(xué)好IO,必須要清楚抽象類、IO的操作部分掌握兩個(gè)代碼模型。IO的核心組成五個(gè)類(File、OutputStream、InputStream、Writer、Reader)一個(gè)接口(Serializable)。
再java.io是一個(gè)與文本本身操作有關(guān)的程序(創(chuàng)建、刪除、信息取得—)
如果要想使用File類操作文件的話,那么肯定要通過構(gòu)造方法實(shí)例化File類對象,而實(shí)例化File類對象的過程之中主要使用以下兩種構(gòu)造方法:
- 方法一:public File(String pathname);
- 方法二:public File(File parent,String child).
文件的基本操作,主要有以下幾種功能:
- **創(chuàng)建一個(gè)新文件:**public boolean createNewFile() throws IOException
- **刪除文件:**public Boolean delete();
- **判斷路徑是否存在:**public Boolean exists();
創(chuàng)建新文件
package com.day14.demo;
import java.io.File;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args) throws IOException {
File file = new File("f:\\hello.txt");
file.createNewFile();
}
}
如果文件存在進(jìn)行刪除,不存在進(jìn)行創(chuàng)建
package com.day14.demo;
import java.io.File;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args) throws IOException {
File file = new File("f:\\hello.txt");
if(file.exists()){//文件存在
file.delete();
}else{//文件不存在
file.createNewFile();//創(chuàng)建文件
}
}
}
本程序操作就表示如果文件存在則刪除,如果不存在則創(chuàng)建一個(gè)新的文件,此時(shí)基本功能是實(shí)現(xiàn)了,不過這個(gè)程序此時(shí)存在三個(gè)問題:
問題一:關(guān)于路徑的分隔符
在windows操作之中,使用“\”作為路徑分隔符,而在Linux系統(tǒng)下使用“/”作為路徑分隔符,而實(shí)際的開發(fā)而言,大部分情況下會在windows中做開發(fā),而后將項(xiàng)目部署在Linus,那么此時(shí),路徑的分隔符都需要進(jìn)行修改,這樣實(shí)在是國語麻煩,為此在File類之中提供了一個(gè)常量:public static final String separator(按照J(rèn)ava的命名規(guī)范來講,對于全局常量應(yīng)該使用大寫字母的方式定義,而此處使用的是小寫,是由Java的發(fā)展歷史所帶來的問題)。
//由不同的操作系統(tǒng)的JVM來決定最終的separator是什么內(nèi)容File file = new File("f:" + File.separator + "hello.txt");
問題二:是有可能會出現(xiàn)的延遲問題
發(fā)現(xiàn)程序執(zhí)行完成之后,對于文件的創(chuàng)建或者是刪除是會存在一些操作上的延遲,如果現(xiàn)在假設(shè)先刪除了一個(gè)文件,而后立刻判斷此文件是否存在,那么可能得到的結(jié)果就是錯(cuò)誤的(為true),一位所有的*.class文件都要通過JVM與操作系統(tǒng)間接操作,這樣就有可能會出現(xiàn)延遲的問題。

問題三:目錄問題
之前進(jìn)行文件創(chuàng)建的時(shí)候都是在根目錄下創(chuàng)建完成的,如果說現(xiàn)在要?jiǎng)?chuàng)建的文件有目錄呢?例如,現(xiàn)在要?jiǎng)?chuàng)建一個(gè)f:\hello\hello.txt文件,而此時(shí)在執(zhí)行程序的時(shí)候hello目錄不存在,這個(gè)時(shí)候執(zhí)行的話就會出現(xiàn)錯(cuò)誤提示:
Exception in thread "main" java.io.IOException: 系統(tǒng)找不到指定的路徑。
因?yàn)楝F(xiàn)在目錄不存在,所以不能創(chuàng)建,那么這個(gè)時(shí)候必須首先判斷要?jiǎng)?chuàng)建文件的父路徑是否存在,如果不存在應(yīng)該創(chuàng)建一個(gè)目錄,之后再進(jìn)行文件的創(chuàng)建,而要想完成這樣的操作,需要一下幾個(gè)方法支持:
**找到一個(gè)指定文件的父路徑:**public File getParentFile();
**創(chuàng)建目錄:**public boolean mldirs()。
package com.day14.demo;
import java.io.File;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args) throws IOException {
//由不同的操作系統(tǒng)的JVM來決定最終的separator是什么內(nèi)容
File file = new File("f:" + File.separator +"hello" + File.separator + "hello.txt");
if(!file.getParentFile().exists()){//父目錄
file.getParentFile().mkdirs();//創(chuàng)建父目錄
}
if(file.exists()){//文件存在
file.delete();
}else{//文件不存在
file.createNewFile();//創(chuàng)建文件
}
}
}
以后在任何的java.io.File類開發(fā)過程之中,都一定要考慮文件目錄的問題。
5.2 取得文件信息
在File類之中還可以通過以下的方法取得一些文件的基本信息:
| 方法名稱 | 描述 |
| public String getName() | 取得文件的名稱 |
| public boolean isDirectory() | 給定的路徑是否為文件夾 |
| public boolean isFile() | 給定的路徑是否是文件 |
| public boolean isHidden() | 是否是隱藏文件 |
| public long lastModified() | 文件的最后一次修改日期 |
| public long length() | 取得文件大小,是以字節(jié)為單位返回的。 |
獲取文件的大小信息以及核心信息
package com.day14.demo;import java.io.File;import java.math.BigDecimal;import java.text.SimpleDateFormat;import java.util.Date;class MyMath{ public static double round(double num, int scale){ return Math.round(num * Math.pow(10, scale)) / Math.pow(10, scale); }}public class FileDemo2 { public static void main(String[] args) { File file = new File("f:" + File.separator + "701_03_支付寶沙箱使用.avi"); if(file.exists() && file.isFile()){ System.out.println("1文件大小為:" + MyMath.round(file.length() / (double) 1024 / 1024, 2)); System.out.println("最后一次修改日期:"+ new SimpleDateFormat("YYYY-MM-dd HH:mm:ss").format(new Date(file.lastModified()))); System.out.println("2文件大小為:" + new BigDecimal(file.length() / (double)1024 /1024).divide(new BigDecimal(1), 2, BigDecimal.ROUND_HALF_UP).doubleValue()); } }}
**列出目錄內(nèi)容:**public File [] listFiles(),此方法將目錄中的所有文件以File對象數(shù)組的方式返回;
列出目錄的所有結(jié)構(gòu)
package com.day14.demo;
import java.io.File;
import java.util.Arrays;
public class FileDemo3 {
public static void main(String[] args) {
File file = new File("f:" + File.separator);
if(file.exists() && file.isDirectory()){
File[] listFiles = file.listFiles();
System.out.println(Arrays.toString(listFiles));
}
}
}
5.3 綜合案例:目錄列表
現(xiàn)在希望把一個(gè)目錄下的全部文件都列出來,那么這種情況下只能采用遞歸:因?yàn)榱谐鲆粋€(gè)目錄下的全部文件或著文件夾之后,如果發(fā)現(xiàn)列出的內(nèi)容是文件夾,則應(yīng)該向后繼續(xù)列出。
列出指定目錄下的所有文件
package com.day14.demo;
import java.io.File;
public class FileListDemo {
public static void main(String[] args) {
File file = new File("f:" + File.separator);
list(file);
}
public static void list(File file){
if(file.isDirectory()){
File[] files = file.listFiles();
if(files != null){
for (int i = 0; i < files.length; i++) {
list(files[i]);//繼續(xù)列出
}
}
}
System.out.println(file);
}
}
線程阻塞問題
現(xiàn)在代碼都在main線程下執(zhí)行,如果該程序執(zhí)行完成后才能繼續(xù)執(zhí)行下一條語句,要想解決這種耗時(shí)的問題。最好產(chǎn)生一個(gè)新的線程進(jìn)行列出。
package com.day14.demo;import java.io.File;public class FileListDemo { public static void main(String[] args) { new Thread(()->{ File file = new File("f:" + File.separator); list(file); },"列出線程").start(); System.out.println("開始進(jìn)行文件信息列出。。。。"); } public static void list(File file){ if(file.isDirectory()){ File[] files = file.listFiles(); if(files != null){ for (int i = 0; i < files.length; i++) { list(files[i]);//繼續(xù)列出 } } } System.out.println(file); }}
6、IO— 字節(jié)流與字符流

字符流和字節(jié)流最本質(zhì)的區(qū)別就是只有一個(gè)字節(jié)流是原生的操作,二字符流是經(jīng)過處理后的操作。經(jīng)過磁盤數(shù)據(jù)保存所保存的支持的數(shù)據(jù)類型只有:字節(jié),所有磁盤中的數(shù)據(jù)必須先讀到內(nèi)存后才可以操作,內(nèi)存里面會幫助我們把字節(jié)變?yōu)樽址W址舆m合處理中文。
**字節(jié)操作流:**OutputStream,InputStream;
**字符操作流:**Writer,Reader。
但是不管是字節(jié)流還是字符流的操作,本身都表示資源操作,而執(zhí)行所有的資源都會按照如下幾個(gè)步驟進(jìn)行,下面以文件操作為例(對文件進(jìn)行讀,寫操作):
- 要根據(jù)文件創(chuàng)建File對象
- 根據(jù)字節(jié)流或字符流的子類實(shí)例化我們的父類對象
- 進(jìn)行數(shù)據(jù)的讀取、寫入操作
- 關(guān)閉流(clone())
對于IO操作屬于資源處理,所有的對于資源的處理進(jìn)行處理完成后必須進(jìn)行關(guān)閉,否則資源就再也無法執(zhí)行。
6.1 字節(jié)輸出流:OutputStream
Java.io.OutputStream主要的功能是進(jìn)行字節(jié)數(shù)據(jù)的輸出的,而這個(gè)類的定義如下:
public abstract class OutputStream extends Object implements Closeable, Flushable
發(fā)現(xiàn)OutputStream類定義的時(shí)候?qū)崿F(xiàn)了兩個(gè)接口:Closeable,Flushable,這兩個(gè)接口定義如下:
| Closeable: | Flushable: |
| public interface Closeable extends AutoCloseable{ public void close() throws IOException; } |
public interface Closeable{ public void flush() throws IOException; } |
當(dāng)取得了OutputStream類實(shí)例化對象之后,下面肯定要進(jìn)行輸出操作,在OutputStream類之中定義了三個(gè)方法:
**輸出單個(gè)字節(jié)數(shù)組數(shù)據(jù):**public abstract void write(int b) throws IOException
**輸出一組字節(jié)數(shù)組數(shù)據(jù):**public void write(byte[] b) throws IOException
**輸出部分字節(jié)數(shù)組數(shù)據(jù):**public void write(byte[] b,int off,int len) throws IOException
提示:對于Closeable繼承的AutoCloseable接口
AuotCloseable實(shí)在JDK1.7的時(shí)候又增加了一個(gè)新的接口,但是這個(gè)接口的定義和Closeable定義是完全一樣的,我個(gè)人認(rèn)為:有可能在一些其他的類上出現(xiàn)了自動(dòng)的關(guān)閉功能,Closeable是手工關(guān)閉,AutoCloseable屬于自動(dòng)關(guān)閉。
但是對于Closeable和Flushable這兩個(gè)接口實(shí)話而言不需要關(guān)注,因?yàn)閺淖钤绲牧?xí)慣對于flush()和close()連個(gè)方法都是直接在OutputStream類之中定義的,所以很少去關(guān)心這些父接口問題。
對于OutputStream類而言發(fā)現(xiàn)其本身定義的是一個(gè)抽象類(abstract class),按照抽象類的使用原則來講,如果要想為父類實(shí)例化,那么就需要使用子類,就需要定義抽象的子類,而現(xiàn)在如果要執(zhí)行的是文件操作,則可以使用FileOutputStream子類完成。如果按照面向?qū)ο蟮拈_發(fā)原則,子類要為抽象類進(jìn)行對象的實(shí)例化,而后調(diào)用的方法以父類中定義的方法為主,而具體的實(shí)現(xiàn)找實(shí)例化這個(gè)父類的子類完成,也就是說在整個(gè)的操作之中,用戶最關(guān)心的只有子類的構(gòu)造方法:
**實(shí)例化FileOutputStream(新建數(shù)據(jù)):**public FileOutputStream([File file) throws FileNotFoundException
**實(shí)例化FileOutputStream(追加數(shù)據(jù)):**public FileOutputStream(File file,boolean append) throws FileNotFoundException

實(shí)現(xiàn)文件內(nèi)容的輸出
package com.day14.demo;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
public class OutputDemo {
public static void main(String[] args) throws Exception {
//1.定義文件路徑
File file = new File("f:" + File.separator + "test" + File.separator + "hello.txt");
if(!file.getParentFile().exists()){//父路徑不存在
file.getParentFile().mkdirs();//創(chuàng)建父目錄
}
//2.要輸出的數(shù)據(jù)
String str = "Hello,zsr!!!!";
//3.實(shí)例化對象
FileOutputStream stream = new FileOutputStream(file);
//4.將內(nèi)容寫進(jìn)stream
stream.write(str.getBytes());//輸出數(shù)據(jù),要將輸出的數(shù)據(jù)變?yōu)樽止?jié)數(shù)組輸出
//5.關(guān)閉流
stream.close();
}
}
這里默認(rèn)執(zhí)行時(shí)進(jìn)行文檔內(nèi)容的覆寫,如果不希望進(jìn)行文檔內(nèi)容的覆寫可以直接將FileOutputStream改為
FileOutputStream stream = new FileOutputStream(file,true);
如果對寫入的內(nèi)容需要換行操作必須使用\r\n進(jìn)行換行操作。
6.2 字節(jié)輸入流:InputStream
如果現(xiàn)在要從指定的數(shù)據(jù)源之中讀取數(shù)據(jù),使用InputStream,而這個(gè)類的定義如下:
public abstract class InputStreamextends Objectimplements Closeable
發(fā)現(xiàn)InputStream只實(shí)現(xiàn)了Closeable接口
在InputStream之中定義了三個(gè)讀取數(shù)據(jù)的方法:
**讀取單個(gè)字節(jié):**public abstract int read() throws IOException
**說明:**每次執(zhí)行read()方法都會讀取一個(gè)數(shù)據(jù)源的指定數(shù)據(jù),如果現(xiàn)在發(fā)現(xiàn)已經(jīng)讀取到了結(jié)尾則返回-1.
**讀取多個(gè)字節(jié):**public int read(byte[] b) throws IOException
**說明:**如果現(xiàn)在要讀取的數(shù)據(jù)小于開辟的字節(jié)數(shù)組,這個(gè)時(shí)候read()方法的返回值int返回的是數(shù)據(jù)個(gè)數(shù);如果現(xiàn)在開辟的字節(jié)數(shù)組小于讀取的長度,則這個(gè)時(shí)候返回就是長度;如果數(shù)據(jù)已經(jīng)讀完了,則這個(gè)時(shí)候的int返回的是-1.
**讀取指定多個(gè)字節(jié):**public int read(byte[] b,int off,int len) throws IOException
**說明:**每次只讀取傳遞數(shù)組的部分內(nèi)容,如果讀取滿了,返回就是長度;如果沒有讀取滿,返回的就是讀取的個(gè)數(shù);如果讀取到最后沒有數(shù)據(jù)了,就返回-1

既然InputStream為抽象類,那么這個(gè)抽象類要使用就必須有子類,現(xiàn)在是通過文件讀取內(nèi)容,肯定使用FileInputStream子類進(jìn)行操作,與OutputStream類的使用一樣,對于FileInputStream也只關(guān)心構(gòu)造方法:
**FileInputStream****類構(gòu)造方法:public FileInputStream(File file) throws FileNotFoundException
文件信息的讀取
package com.day14.demo;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class InputDemo {
public static void main(String[] args) throws Exception {
File file = new File("f:" + File.separator + "test" + File.separator + "hello.txt");
if(!file.exists()){
System.out.println("指定文件不存在!!");
}else{
FileInputStream is = new FileInputStream(file);
byte[] result = new byte[1024];
int length = is.read(result);
System.out.println("讀取的內(nèi)容為:" + new String(result,0,length));
}
}
}
6.3 字符輸出流:Writer
Writer類也是一個(gè)專門用來數(shù)據(jù)輸出的操作類,對于中文數(shù)據(jù)來說是比較友好的,這個(gè)類定義:
public abstract class Writer extends Object implements Appendable, Closeable, Flushable
在Writer類之中定義的writer()方法都是以字符數(shù)據(jù)為主,但是在這些方法之中,只關(guān)心一個(gè):
**輸出一個(gè)字符串:**public void write(String str) throws IOException
如果要操作文件肯定使用FileWriter子類。
package com.day14.demo;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class WriterDemo {
public static void main(String[] args) throws IOException {
//1.定義文件路徑
File file = new File("f:" + File.separator + "test" + File.separator + "hello.txt");
if(!file.getParentFile().exists()){//父路徑不存在
file.getParentFile().mkdirs();//創(chuàng)建父目錄
}
//2.要輸出的數(shù)據(jù)
String str = "我正在學(xué)java這門課程?。。。r\n";
//如果想要進(jìn)行內(nèi)容不覆蓋的直接使用true就可以了
//FileWriter out = new FileWriter(file,true);
FileWriter out = new FileWriter(file);
out.write(str);
out.close();
}
}
6.4 字符輸入流:Reader
Reader是進(jìn)行字符數(shù)據(jù)讀取的一個(gè)操作類,其定義:
public abstract class Reader extends Object implements Readable, Closeable
在Writer類之中存在了直接輸出一個(gè)字符串?dāng)?shù)據(jù)的方法,可是在Reader類之中并沒有定義這樣的方法,只是定義了三個(gè)按照字符串讀取的方法?為什么會這樣?
因?yàn)樵谑褂肙utputStream輸出數(shù)據(jù)的時(shí)候,其程序可以輸出的大小一定是程序可以承受的數(shù)據(jù)的大小,那么如果說使用InputStream讀取的時(shí)候,可能被讀取的數(shù)據(jù)非常大,那么如果一次性全讀進(jìn)來,就會出現(xiàn)問題,所以只能一個(gè)一個(gè)的進(jìn)行讀取。
Reader依然是抽象類,那么如果從文件讀取,依然使用FileReader類
package com.day14.demo;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ReadDemo {
public static void main(String[] args) throws IOException {
File file = new File("f:" + File.separator + "test" + File.separator + "hello.txt");
if(!file.exists()){
System.out.println("指定文件不存在??!");
}else{
FileReader reader = new FileReader(file);
char[] result = new char[1024];
int length = reader.read(result);
System.out.println("讀取的內(nèi)容為:" + new String(result,0,length));
}
}
}
字符比字節(jié)的好處就是在于字符串?dāng)?shù)據(jù)的支持上,而這個(gè)好處還只是在Writer()類中體現(xiàn),所以與字節(jié)流相比,字符流的操作并不是對等的關(guān)系。
6.5 字節(jié)流與字符流區(qū)別
通過我們一系統(tǒng)的分析,可以發(fā)現(xiàn)字節(jié)流和字符流的代碼操作區(qū)別不大,如果從我們實(shí)際的使用,我們字節(jié)流是優(yōu)先考慮,只有再我們使用中文的時(shí)候才考慮使用字符流,因?yàn)樗械淖址夹枰ㄟ^內(nèi)存緩沖來進(jìn)行處理。

既然讀數(shù)據(jù)需要緩存的處理,那么寫數(shù)據(jù)也同樣需要。如果使用字符流沒有進(jìn)行刷新,那么我們的內(nèi)容可能再緩存之中,所以必須進(jìn)行強(qiáng)制刷新才能得到完整的數(shù)據(jù)內(nèi)容。
package com.day14.demo;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class WriterDemo {
public static void main(String[] args) throws IOException {
//1.定義文件路徑
File file = new File("f:" + File.separator + "test" + File.separator + "hello.txt");
if(!file.getParentFile().exists()){//父路徑不存在
file.getParentFile().mkdirs();//創(chuàng)建父目錄
}
//2.要輸出的數(shù)據(jù)
String str = "我正在學(xué)java這門課程?。。?!\r\n";
//如果想要進(jìn)行內(nèi)容不覆蓋的直接使用true就可以了
//FileWriter out = new FileWriter(file,true);
FileWriter out = new FileWriter(file);
out.write(str);
out.flush();
}
}
在以后的IO處理的時(shí)候,如果處理的是圖片、音樂、文字都可以使用字節(jié)流,只有再處理中文的時(shí)候才會使用字符流。
7、轉(zhuǎn)換流
現(xiàn)在對于IO操作就存在了字節(jié)流和字符流兩種操作,那么對于這兩種操作流之間也是可以進(jìn)行轉(zhuǎn)換的,而轉(zhuǎn)換的操作類有兩個(gè):
將字節(jié)輸出流變?yōu)樽址敵隽鳎∣utputStream->Writer)——OutputStreamWriter;
將字節(jié)輸入流變?yōu)樽址斎肓鳎↖nputStream->Reader)——InputStreaReader。
| OutputStreamWriter | InputStreamReader |
| public class OutputStreamWriter extends Writer | public class InputStreamReader extends Reader |
| public OutputStreamWriter(OutputStream out) | public InputStreamReader(InputStream in) |

通過以上的繼承結(jié)構(gòu)和構(gòu)造方法可以清楚發(fā)現(xiàn),既然OutputStreamWriter是Writer的子類,那么必然OutputStreamWriter可以通過Writer類執(zhí)行對象的向上轉(zhuǎn)型進(jìn)行接收,而同時(shí)這個(gè)OutputStreamWriter類的構(gòu)造方法可以接收OutputStream,這樣就可以完成轉(zhuǎn)型。
將字節(jié)輸出流變?yōu)樽址敵隽?/p>
package com.day14.demo;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
public class OutWriterDemo {
public static void main(String[] args) throws Exception {
//1.定義文件路徑
File file = new File("f:" + File.separator + "test" + File.separator + "hello.txt");
if(!file.getParentFile().exists()){//父路徑不存在
file.getParentFile().mkdirs();//創(chuàng)建父目錄
}
//2.要輸出的數(shù)據(jù)
String str = "Hello,world!!!!";
//3.實(shí)例化對象
OutputStream stream = new FileOutputStream(file,true);
//4.將內(nèi)容寫進(jìn)stream
Writer out = new OutputStreamWriter(stream);
out.write(str);
//5.關(guān)閉流
out.close();
}
}
對于文件操作可以使用FileInputStream,F(xiàn)ileOutputStream,F(xiàn)ileReader,F(xiàn)ileWriter四個(gè)類,那么下面分別觀察這四個(gè)類的繼承結(jié)構(gòu)。
觀察FileInputStream,F(xiàn)ileOutoutStream類的繼承結(jié)構(gòu)
| FileInputStream | FileOutoutStream |
| java.lang.Object java.io.InputStream java.io.FilterInputStream |
java.lang.Object java.io.OutputStream java.io.FileOutputStream |
觀察FileReader,F(xiàn)ileWriter類的繼承結(jié)構(gòu)
| FileReader | FileWrite |
| java.lang.Object java.io.Reader java.io.InputStreamReader java.io.FileReader |
java.lang.Object java.io.Writer java.io.OutputStreamWriter java.io.FileWriter |

通過以上的繼承關(guān)系也可以發(fā)現(xiàn),實(shí)際上所有的字符數(shù)據(jù)都是需要進(jìn)行轉(zhuǎn)換的,依靠轉(zhuǎn)換流完成,以后真正保存或者是傳輸?shù)臄?shù)據(jù)是不可能有字符的,全部都是字節(jié),而字節(jié)只是在電腦之中處理后的結(jié)果。
到此這篇關(guān)于Day14基礎(chǔ)不牢地動(dòng)山搖-Java基礎(chǔ)的文章就介紹到這了,更多相關(guān)Java基礎(chǔ)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring整合shiro框架的實(shí)現(xiàn)步驟記錄
Shiro是一個(gè)強(qiáng)大易用的Java安全框架,提供了認(rèn)證、授權(quán)、加密和會話管理等功能。下面這篇文章主要給大家介紹了關(guān)于spring整合shiro框架的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2018-05-05
SpringBoot配置log4j2的實(shí)現(xiàn)示例
SpringBoot中默認(rèn)使用Logback作為日志框架,本文主要介紹了SpringBoot配置log4j2的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12
Java中equals()方法重寫實(shí)現(xiàn)代碼
這篇文章主要介紹了Java中equals()方法重寫實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-05-05
swing組件JScrollPane滾動(dòng)條實(shí)例代碼
這篇文章主要介紹了swing組件JScrollPane滾動(dòng)條實(shí)例代碼,分享了兩個(gè)相關(guān)代碼示例,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02

