这里主要谈一下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();
}
}