本文章参考郭霖老师第一行代码第二版的第六章,然后总结了一下并且加上自己的理解
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数据库的最好的实践
先说一些基本常用的语句:
打开数据库:
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));
然后再说一些概念
首先我们找到我们SDK文件夹中的adb,C:\Users\dell\AppData\Local\Android\Sdk\platform-tools(你们电脑中的adb地址,我这里只是举了我自己电脑adb的地址)
然后在电脑的属性-高级系统设置-环境变量-系统变量中的Path将上面的地址复制粘贴过去
如图:
我们这里要用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();
}
});
}
}
用cmd查看数据库信息:(我这里的模拟器用的AS自带的模拟器安卓版本为6.0,系统为7.0的模拟器好像用不了,如果是手机的话要root)
通过命令行就可以看到我们创建的表,这里我创建了一个book,一个press表
一开始查询:
添加一条信息点击添加:
添加之后我们再查一遍:
看到了我们有了一条新加的消息.
然后我们点击删除,删除之后再查就什么都没有了