這裏主要談一下BufferedReader以及ByteArrayOutputStream
關於ByteArray
先看看API文檔上說的
ByteArrayInputStream
包含一個內部緩衝區,該緩衝區包含從流中讀取的字節。內部計數器跟蹤read
方法要提供的下一個字節。
關閉 ByteArrayInputStream 無效。此類中的方法在關閉此流後仍可被調用,而不會產生任何IOException。
此類實現了一個輸出流,其中的數據被寫入一個 byte 數組。緩衝區會隨着數據的不斷寫入而自動增長。可使用 toByteArray()和 toString()獲取數據
我的個人理解是ByteArrayOutputStream是用來緩存數據的(數據寫入的目標(output stream原義)),向它的內部緩衝區寫入數據,緩衝區自動增長,當寫入完成時可以從中提取數據。由於這個原因,ByteArrayOutputStream常用於存儲數據以用於一次寫入。
這個類實際上是把別的流讀取的內容寫到自己的緩存裏面,然後可以用toString方法獲取到
我個人經常用到的一個工具包
/*
* 從外部傳入一個輸入流
* 讀取輸入流的內容寫到緩存中
*/
public class WebUtils {
public static String gettextFromInputStream(InputStream is ,String charset){
String text = null;
if(charset==null){
charset="utf-8";
}
try {
ByteArrayOutputStream baos= new ByteArrayOutputStream();
//帶緩存的按字節讀取輸入流
byte[] b = new byte[1024];
int len = 0;
while ((len=is.read(b))!=-1) {
//讀取的內容寫入到ByteArray
baos.write(b, 0, len);
}
baos.close();
//讀取其中的內容需要用到toByteArray或者toString
text = new String(baos.toByteArray(), charset);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return text;
}
}
關於BufferedReader
API文檔中的描述
從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取。
可以指定緩衝區的大小,或者可使用默認的大小。大多數情況下,默認值就足夠大了。
通常,Reader 所作的每個讀取請求都會導致對底層字符或字節流進行相應的讀取請求。因此,建議用 BufferedReader 包裝所有其 read() 操作可能開銷很高的 Reader(如 FileReader 和 InputStreamReader)。例如,
BufferedReader in = new BufferedReader(new FileReader("foo.in"));將緩衝指定文件的輸入。如果沒有緩衝,則每次調用 read() 或 readLine() 都會導致從文件中讀取字節,並將其轉換爲字符後返回,而這是極其低效的。
通過用合適的 BufferedReader 替代每個 DataInputStream,可以對將 DataInputStream 用於文字輸入的程序進行本地化。
他是一個包裝類,將別的輸入流傳進來,緩存起來,然後等到緩存滿了一次性讀取,然後可以按行讀取,這樣效率提高了不少。
1. 當BufferedReader在讀取文本文件時,會先儘量從文件中讀入字符數據並置入緩衝區,而之後若使用read()方法,會先從緩衝區中進行讀取。如果緩衝區數據不足,纔會再從文件中讀取,使用BufferedWriter時,寫入的數據並不會先輸出到目的地,而是先存儲至緩衝區中。如果緩衝區中的數據滿了,纔會一次對目的地進行寫出。
2. 從標準輸入流System.in中直接讀取使用者輸入時,使用者每輸入一個字符,System.in就讀取一個字符。爲了能一次讀取一行使用者的輸入,使用了BufferedReader來對使用者輸入的字符進行緩衝。readLine()方法會在讀取到使用者的換行字符時,再一次將整行字符串傳入。
3. System.in是一個位流,爲了轉換爲字符流,可使用InputStreamReader爲其進行字符轉換,然後再使用BufferedReader爲其增加緩衝功能。
BufferedOutputStream會首先創建一個默認的容器量, capacity = 8192 = 8KB, 每次在寫的時候都會去比對capacity是否還夠用, 如果不夠用的時候, 就flushBuffer(), 把buf中的數據寫入對應的outputStream中, 然後將buf清空, 一直這樣等到把內容寫完. 在這過程中主要起到了一個數據緩衝的功能.
登錄實例:
讓用戶點擊一個checkbox確定是否保存賬戶密碼,下次登錄直接讀取
第一類,直接存入到apk安裝目錄下,專屬空間,無需權限
<pre name="code" class="java">public class MainActivity extends Activity {
EditText et_username =null;
EditText et_password =null;
Button bt_login =null;
CheckBox cb_remeber = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//button
et_username = (EditText) findViewById(R.id.et_uername);
et_password = (EditText) findViewById(R.id.et_password);
bt_login = (Button) findViewById(R.id.bt_login);
cb_remeber = (CheckBox) findViewById(R.id.cb_remeber);
//讀取保存的賬戶信息
readAccount();
}
//button響應,需要保存賬戶密碼
public void login(View view) {
//checkbox勾上了才保存
if(cb_remeber.isChecked()){
//獲取到textview上的string型數據
String username= et_username.getText().toString();
String password= et_password.getText().toString();
//android默認的保存路徑,可以通過getcachedir來獲取,不用自己寫
//File file = new File("/data/data/com.cskaoyan.login/userinfo.txt");
File file = new File(getCacheDir() ,"userinfo2.txt");
FileWriter fw=null;
try {
fw = new FileWriter(file);
fw.write(username+","+password);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//不爲空的時候才關閉
if (fw!=null)
try {
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
private void readAccount() {
// 文件來源
File file = new File(getCacheDir(),"userinfo2.txt");
//存在纔讀取
if(file.exists()){
//finally裏關閉流,必須有初始化,單單聲明還不行
FileReader fr=null;
BufferedReader br=null;
try {
//bufferedreader是包裝類,需要包裝一個輸入流進來
fr = new FileReader(file);
br = new BufferedReader(fr);
//按行讀取,並且以逗號切取存入到數組
String line = br.readLine();
String s[] = line.split(",");
String username = s[0];
String password = s[1];
//顯示到textview
et_password.setText(password);
et_username.setText(username);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
fr.close();
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
第二類,如果把文件寫到SD卡上,需要注意檢查SD卡的狀態,Environment類,另外需要相關權限
<pre name="code" class="java">public class MainActivity extends Activity {
EditText et_username =null;
EditText et_password =null;
CheckBox cb_remeber = null;
Button bt_login =null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_username = (EditText) findViewById(R.id.et_uername);
et_password = (EditText) findViewById(R.id.et_password);
cb_remeber = (CheckBox) findViewById(R.id.cb_remeber);
bt_login = (Button) findViewById(R.id.bt_login);
readAccount();
}
private void readAccount() {
File sdcard = Environment.getExternalStorageDirectory();
File file = new File(sdcard , "userinfo.txt");
if (file.exists()) {
FileReader fReader = null;
BufferedReader br =null;
try {
fReader = new FileReader(file);
br = new BufferedReader(fReader);
String line = br.readLine();
String[] s= line.split(",");
String username = s[0];
String passwrod = s[1];
et_username.setText(username);
et_password.setText(passwrod);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
try {
fReader.close();
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public void login(View v) {
if(cb_remeber.isChecked()){
String username= et_username.getText().toString();
String password= et_password.getText().toString();
//sd卡路徑
File sdcard = Environment.getExternalStorageDirectory();
//需要檢查sd卡狀態,正常掛載時才進行操作
if ("mounted".equals(Environment.getExternalStorageState())) {
File file = new File(sdcard , "userinfo.txt");
FileWriter fw=null;
try {
fw = new FileWriter(file);
fw.write(username+","+password);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (fw!=null)
try {
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
第三類,寫到服務器上,需要前面提到的工具類
這涉及到服務器端和客戶端的網絡連接問題
請求的方式又分爲post和get,這裏get有一個問題要注意,由於需要在請求頭中轉碼,有可能會造成編碼不一致的問題,需要在服務器端處理;相對來說,post簡單一點
這裏不細說了~
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
Handler hanlder = new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case 1:
Toast.makeText(MainActivity.this, (String)msg.obj, 1).show();
break;
case 2:
Toast.makeText(MainActivity.this, (String)msg.obj, 0).show();
break;
default:
break;
}
}
};
//get方式
public void login(View v){
EditText et_username = (EditText)findViewById(R.id.et_uername);
EditText et_password = (EditText)findViewById(R.id.et_password);
final String username= et_username.getText().toString();
final String password= et_password.getText().toString();
Thread thread = new Thread(){
public void run(){
String path = "http://192.168.137.1/LoginDemo/servlet/Login?username="+URLEncoder.encode(username)+"&password="+password;
try {
URL url = new URL(path);
HttpURLConnection conn= (HttpURLConnection) url.openConnection();
conn.setReadTimeout(5000);
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
conn.connect();
if(conn.getResponseCode()==200){
InputStream is= conn.getInputStream();
String text =WebUtils.gettextFromInputStream(is, null);
Message msg = hanlder.obtainMessage();
msg.what=1;
msg.obj=text;
hanlder.sendMessage(msg);
}
else {
Message msg = hanlder.obtainMessage();
msg.what=2;
msg.obj="連接服務器失敗";
hanlder.sendMessage(msg);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
thread.start();
}
//post方式
public void login2(View v){
EditText et_username = (EditText)findViewById(R.id.et_uername);
EditText et_password = (EditText)findViewById(R.id.et_password);
final String username= et_username.getText().toString();
final String password= et_password.getText().toString();
Thread thread = new Thread(){
public void run(){
String path = "http://192.168.137.1/LoginDemo/servlet/Login";
String data = "username="+URLEncoder.encode(username)+"&password="+password;
try {
URL url = new URL(path);
HttpURLConnection conn= (HttpURLConnection) url.openConnection();
conn.setReadTimeout(5000);
conn.setConnectTimeout(5000);
conn.setRequestMethod("POST");
conn.setRequestProperty("content-Length", data.length()+"");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
conn.connect();
if(conn.getResponseCode()==200){
InputStream is= conn.getInputStream();
String text =WebUtils.gettextFromInputStream(is, null);
Message msg = hanlder.obtainMessage();
msg.what=1;
msg.obj=text;
hanlder.sendMessage(msg);
}
else {
Message msg = hanlder.obtainMessage();
msg.what=2;
msg.obj="連接服務器失敗";
hanlder.sendMessage(msg);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
thread.start();
}
}