本文章参考郭霖老师第一行代码第二版的第六章,然后总结了一下并且加上自己的理解
1.文件存储
openFileOutput()方法,第一个参数是字符串或文件名(不包括路径,因为有默认路径),第二个参数为文件的操作模式,MODE_PRIVATE覆盖源文件,MODE_APPEND为往原文件里添加内容.
openFileOutput()方法返回的是一个FileOutputStream对象.
随便说一下java.IO层次体系结构:
主要的类如下:
1. File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。
2. InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。
3. OutputStream(二进制格式操作):抽象类,基于字节的输出操作,是所有输出流的父类。定义了所有输出流都具有的共同特征。
Java中字符是采用Unicode标准,一个字符是16位,即一个字符使用两个字节来表示。为此,JAVA中引入了处理字符的流。
4. Reader(文件格式操作):抽象类,基于字符的输入操作。
5. Writer(文件格式操作):抽象类,基于字符的输出操作.
还有一行这样代码来举例:
//缓冲流 字符流 装饰字节流 字节流
bufferedReader = new BufferedReader(new InputStreamReader(new DataInputStream(socket.getInputStream())));
问题①
如果只用FileOutputStream fileOutputStream = new FileOutputStream("d:/text.txt");
不是也能输出到"d:/text.txt"吗?
为什么要用其它两个呢?能起到什么作用呢?
FileOutputStream 是字节流,它一个字节一个字节的向外边送数据
OutputStreamWrite是字符流,它一个字符一个字符的向外边送数据
它们有什么区别么?
解析:
因为计算机是西方发明的,它们的英文字符占一个字节,而我们的中文是一个字符,占俩字节。如果用stream,你读出来的英语再倒也罢了,读出来的中文可就是乱码或者一个个“??"". 如果你用WRITER,就不会有乱码了
问题②
BufferedWriter Buffer是一个缓冲区,为什么要用BUFFER呢?
如果你直接用stream或者writer,你的硬盘可能就是一个字符或者一个字节 读写硬盘一次,可是你用了Buffer,你的硬盘就是读了一堆数据之后,读写一下硬盘。这样对你硬盘有好处。
实例代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:id="@+id/account"
android:hint="请输入你的账号"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/to_second"
android:text="to_second"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
package com.example.shareprefences;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class MainActivity extends AppCompatActivity {
private EditText account;
private Button to_second;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_2);
account = findViewById(R.id.account);
to_second = findViewById(R.id.to_second);
to_second.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);
}
});
try {
String text = load();
account.setText(text);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
String InputText = account.getText().toString();
try {
save(InputText);
} catch (IOException e) {
e.printStackTrace();
}
}
public void save(String InputText) throws IOException {//把inputtext的存入到data中
FileOutputStream outputStream = null;
BufferedWriter bufferedWriter = null;
outputStream = openFileOutput("data", Context.MODE_PRIVATE);
bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write(InputText);
if(bufferedWriter != null){
bufferedWriter.close();
}
}
public String load() throws IOException {//把data中读取出来
FileInputStream in = null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
in = openFileInput("data");
reader = new BufferedReader(new InputStreamReader(in));
String line = "";
while((line = reader.readLine()) != null){
content.append(line);
}
reader.close();
return content.toString();
}
}
解释:首先用openFileOutput方法转换成FileOutputStream对象outputStream,然后用OutputStreamWriter方法将outputStream转换为BufferedWriter对象,通过BufferedWriter将文本内容写入到文件中.
然后我们在AS菜单栏里View-Tool Windows-Device File Explorer-data-data-com.example.xxx(项目名)-files-data就可以看到我们输入的数据.
②从文件中读取数据
context类提供了openFileInput()方法,用于从文件中读取数据.这个方法要比openFileOutPut()简单,只接受一个参数,即要读取的文件名.并返回一个FileInputStream对象,然后再用java流的方式就可以将数据读取出来了.
解释:首先通过openFileInput()方法获取到了FileInputStream对象in,然后再用InputStreamReader()方法将in转换成BufferedReader对象,这样就可以整行地读取数据了,最后返回content.toString().
2.SharePreferences存储
使用键值对的方式来存储,也就是一个value对应一个key,在读取数据时通过这个key来把这个value取出来,而且SharePreferences支持多种不同的数据类型存储.
要想使用SharePreferences来存储数据,首先获取到SharePreferences对象.
PreferenceManager类中的getDefaultPreference方法
静态方法,只接受一个context参数,
第一步:调用SharePreferences对象的edit方法来获取一个SharePreferences.Editor对象
第二步:向SharePreferences.Editor对象添加数据,如putString().
第三步:调用apply方法,将数据提交,从而进行数据存储操作.
举栗代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".SecondActivity">
<EditText
android:id="@+id/data_1"
android:hint="请输入你的密码"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/save"
android:text="SAVE_DATA"
android:layout_marginEnd="35dp"
android:layout_marginStart="35dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="35dp" />
<Button
android:id="@+id/read"
android:text="READ_DATA"
android:layout_marginEnd="35dp"
android:layout_marginStart="35dp"
android:layout_marginLeft="35dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/data_2"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/to_the_third"
android:text="TO THE THIRD"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
package com.example.shareprefences;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import java.util.prefs.PreferenceChangeEvent;
public class SecondActivity extends AppCompatActivity {
private EditText data_1;
private Button save;
private Button read;
private EditText data_2;
private Button to_third;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
data_1 = findViewById(R.id.data_1);
data_2 = findViewById(R.id.data_2);
save = findViewById(R.id.save);
read = findViewById(R.id.read);
to_third = findViewById(R.id.to_the_third);
save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences.Editor editor =
getSharedPreferences("data", MODE_PRIVATE).edit();
editor.putString("password", String.valueOf(data_1.getText()));
editor.apply();
}
});
read.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences preferences = getSharedPreferences("data",MODE_PRIVATE);
String password = preferences.getString("password","");
data_2.setText(password);
}
});
to_third.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SecondActivity.this,third.class);
startActivity(intent);
}
});
}
}
这里我们把第一个EditText中的数据保存下来,在第二个中读取出来,这里的password就是键,第一个EditText的值就是password键对应的值,所以在第二个里就可以通过password找到相应的值.
然后我们在菜单栏里View-Tool Windows-Device File Explorer-data-data-com.example.xxx(项目名)-share_prefs-data就可以看到我们输入的数据,如果没有点击上边的模拟器刷新一下.
3.数据库存储(Litepal和SQLite)
推荐一下我另外一篇博客,我感觉是对Litepal数据库的最好的实践
先说一些基本常用的语句:
打开数据库:
LitePal.getDatabase();
增:
student.save();
students.add(student);
删:
DataSupport.deleteAll(Saved_Student.class,"account=?",student.getStudent_number());
查:
List<Student> list = DataSupport.where("student_number = ?", ID).find(Student.class);
if (list.size() != 0) {
student = list.get(0);
Log.e("ID:==",student.getStudent_number()+"--------");
}
改:
student.setID_password(MD5HTTL.md5(mess1));
student.updateAll("ID_password=?",MD5HTTL.md5(mess1));
我们这里要用litepal数据库,添加依赖:
api 'org.litepal.android:core:1.4.1'
在manifests中添加:
android:name="org.litepal.LitePalApplication"
创建Book类并继承DataSupport(支持增删查改操作):
public class Book extends DataSupport {
String bookname;
int bookprice;
String author;
public String getBookname() {
return bookname;
}
public void setBookname(String bookname) {
this.bookname = bookname;
}
public int getBookprice() {
return bookprice;
}
public void setBookprice(int bookprice) {
this.bookprice = bookprice;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
然后在Project模式下src-main下新建一个叫assets的directory,然后在里面创建一个New Resource File叫做litepal.xml(Resource type就默认就可以),然后把这个文件移到assets包里面.
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value = "BookStore">
</dbname>
<version value="1"></version>
<list>
<mapping class="com.example.shareprefences.Book"></mapping>
</list>
</litepal>
如果要再添加一个表的话,就在原来的litepal.xml中(value+1,并加上<mapping>):
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value = "BookStore">
</dbname>
<version value="2"></version>
<list>
<mapping class="com.example.shareprefences.Book"></mapping>
<mapping class="com.example.shareprefences.Press"></mapping>
</list>
</litepal>
举栗代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".third">
<Button
android:id="@+id/save_data"
android:text="save_data"
android:layout_marginEnd="45dp"
android:layout_marginStart="45dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/bookname"
android:hint="请输入你想卖的书"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/bookprice"
android:hint="请输入你想卖多少钱"
android:inputType="number|numberDecimal"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/author"
android:hint="请输入书的作者"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/upload"
android:text="添加"
android:textSize="18sp"
android:layout_marginEnd="45dp"
android:layout_marginStart="45dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/delete"
android:text="删除"
android:textSize="18sp"
android:layout_marginEnd="45dp"
android:layout_marginStart="45dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/update"
android:text="更新"
android:textSize="18sp"
android:layout_marginEnd="45dp"
android:layout_marginStart="45dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
界面就这样:(只是举个例子界面不要在意,实现功能就好)
:
public class third extends AppCompatActivity {
private Button save_data;
private EditText bookname;
private EditText bookprice;
private EditText bookauthor;
private Button upload;
private Button delete;
private Button update;
Book book = new Book();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
save_data = findViewById(R.id.save_data);
bookname = findViewById(R.id.bookname);
bookauthor = findViewById(R.id.author);
bookprice = findViewById(R.id.bookprice);
upload = findViewById(R.id.upload);
delete = findViewById(R.id.delete);
update = findViewById(R.id.update);
save_data.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LitePal.getDatabase();
}
});
upload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
book.setBookname(bookname.getText().toString());
book.setAuthor(bookauthor.getText().toString());
book.setBookprice(bookprice.getText().toString());
book.save();
}
});
delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DataSupport.deleteAll(Book.class);
}
});
update.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
book.updateAll();
}
});
}
}
SQLite
数据库创建和升级操作
package com.example.sqlitetest;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;
import androidx.annotation.Nullable;
public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK = "create table Book (" +
"id integer primary key autoincrement," +
"author text," +
"price real," +
"pages integer," +
"name text )";
public static final String CREATE_CATEGORY = "create table Category (" +
"id integer primary key autoincrement," +
"category_name text," +
"category_code integer)";
private Context context;
public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
db.execSQL(CREATE_CATEGORY);
Toast.makeText(context, "Create succeed", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists Book");
db.execSQL("drop table if exists Category");
onCreate(db);
}
}
myDatabaseHelper = new MyDatabaseHelper(this,"BookStore1.db",null,2);
Button button = findViewById(R.id.create);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myDatabaseHelper.getWritableDatabase();
}
});
插入数据
add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = myDatabaseHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", "Da Vinci");
values.put("author", "Dan");
values.put("pages", 454);
values.put("price", 16.96);
//表名,null,ContentValues对象
db.insert("Book", null, values);
values.clear();
values.put("name", "The Lost");
values.put("author", "asd");
values.put("pages", 454);
values.put("price", 16.96);
db.insert("Book", null, values);
}
});
更新数据:
update.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = myDatabaseHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("price", 5.20);
values.put("pages", 554);
db.update("Book", values, "name = ? and pages = ?", new String[]{"Da Vinci","454"});
}
});
删除数据:
delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = myDatabaseHelper.getWritableDatabase();
db.delete("Book", "pages > ?", new String[]{"500"});
}
});
查询数据
query.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = myDatabaseHelper.getWritableDatabase();
Cursor cursor = db.query("Book", null, null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
double price = cursor.getDouble(cursor.getColumnIndex("price"));
Log.e(TAG, "onClick: "+name);
Log.e(TAG, "onClick: "+author );
Log.e(TAG, "onClick: "+pages );
Log.e(TAG, "onClick: "+price);
} while (cursor.moveToNext()) ;
}
cursor.close();
}
});
运行结果:
02-29 22:24:03.962 6106-6106/com.example.sqlitetest E/MainActivity: onClick: The Lost
02-29 22:24:03.962 6106-6106/com.example.sqlitetest E/MainActivity: onClick: asd
02-29 22:24:03.962 6106-6106/com.example.sqlitetest E/MainActivity: onClick: 454
02-29 22:24:03.962 6106-6106/com.example.sqlitetest E/MainActivity: onClick: 16.96