- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Android开发笔记之Android中数据的存储方式(一)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
对于开发平台来讲,如果对数据的存储有良好的支持,那么对应用程序的开发将会有很大的促进作用.
总体的来讲,数据存储方式有三种:一个是文件,一个是数据库,另一个则是网络。其中文件和数据库可能用的稍多一些,文件用起来较为方便,程序可以自己定义格式;数据库用起稍烦锁一些,但它有它的优点,比如在海量数据时性能优越,有查询功能,可以加密,可以加锁,可以跨应用,跨平台等等;网络,则用于比较重要的事情,比如科研,勘探,航空等实时采集到的数据需要马上通过网络传输到数据处理中心进行存储并进行处理,有实时性的需求等.
对于Android平台来讲,它的存储方式也不外乎这几种,按方式总体来分,也是文件,数据库和网络。但我认为从储存标的来讲它可以细分为以下五种方式:
1.1 方式 。
1.Shared Preferences:主要用于保存程序的系统配置信息。用来存储“key-values paires”。一般用于保存程序启动时设定的信息,以便在程序下一次启动时继续保留前一次设定的信息。 2.xml:保存复杂数据,比如短信备份.
3.Files:用文件的形式保存信息。可以通过对文件的读写来获取或保存相关信息.
4.SQLite:用数据库的形式保存信息。SQLite是一个开源的数据库 系统.
5.NetWork:将数据保存于网络.
1.2 区别 。
1. Shared Preferences:
Android提供用来存储一些简单的配置信息的一种机制,例如,一些默认欢迎语、登录的用户名和密码等。其以键值对的方式存储.
SharedPreferences是以XML的格式以文件的方式自动保存的,在DDMS中的File Explorer中展开到/data/data/<packagename>/shared_prefs下,以自己的项目为例,可以看到一个叫做SETTING_Infos.xml的文件 。
2. Files 。
在Android中,其提供了openFileInput 和 openFileOuput 方法读取设备上的文件,下面看个例子代码,具体如下所示:
1
2
3
|
String FILE_NAME =
"tempfile.tmp"
;
//确定要操作文件的文件名
FileOutputStream fos = openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
//初始化
FileInputStream fis = openFileInput(FILE_NAME);
//创建写入流
|
上述代码中两个方法只支持读取该应用目录下的文件,读取非其自身目录下的文件将会抛出异常。需要提醒的是,如果调用FileOutputStream 时指定的文件不存在,Android 会自动创建它,所以不需要判断文件是否存在。另外,在默认情况下,写入的时候会覆盖原文件内容,如果想把新写入的内容附加到原文件内容后,则可以指定其模式为Context.MODE_APPEND,这里涉及到openFileOutput()的四种模式,下文我会详细解释和案例.
3. SQLite 。
SQLite是Android所带的一个标准的数据库,它支持SQL语句,它是一个轻量级的嵌入式数据库 。
4. NetWork:
将数据上传到网络 。
补充:
1.Shared Preferences底层使用xml,xml也可以保存数据,但是Shared Preferences只能保存键值对方式,xml能保存复杂数据 。
2.Content provider底部还是使用了Sqlite数据库,也是算一种方式.
1.3 例子 。
1. Shared Preferences:
小案例:用户输入账号密码,点击登录按钮,登录的同时持久化保存账号和密码 。
用SharedPreference存储账号密码 。
•往SharedPreference里写数据 。
1
2
3
4
5
6
7
|
//拿到一个SharedPreference对象
SharedPreferences sp = getSharedPreferences(
"config"
, MODE_PRIVATE);
//拿到编辑器
Editor ed = sp.edit();
//写数据
ed.putString(
"name"
, name);
ed.commit();
|
注:这里记住put完后,必须commit一下.
•从SharedPreference里取数据 。
1
2
3
|
SharedPreferences sp = getSharedPreferences(
"config"
, MODE_PRIVATE);
//从SharedPreference里取数据
String name = sp.getBoolean(
"name"
,
""
);
|
•代码:
•布局文件 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:paddingBottom=
"@dimen/activity_vertical_margin"
android:paddingLeft=
"@dimen/activity_horizontal_margin"
android:paddingRight=
"@dimen/activity_horizontal_margin"
android:paddingTop=
"@dimen/activity_vertical_margin"
tools:context=
".MainActivity"
android:orientation=
"vertical"
>
<EditText
android:id=
"@+id/et_name"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:hint=
"请输入用户名"
/>
<EditText
android:id=
"@+id/et_pass"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:hint=
"请输入密码"
android:inputType=
"textPassword"
/>
<RelativeLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
>
<CheckBox
android:id=
"@+id/cb"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
"记住用户名和密码"
android:layout_centerVertical=
"true"
/>
<Button
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
"登录"
android:layout_alignParentRight=
"true"
android:onClick=
"login"
/>
</RelativeLayout>
</LinearLayout>
|
•java代码 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
package
com.bokeyuan.sharedpreference;
import
android.os.Bundle;
import
android.app.Activity;
import
android.content.SharedPreferences;
import
android.content.SharedPreferences.Editor;
import
android.view.Menu;
import
android.view.View;
import
android.widget.EditText;
public
class
MainActivity
extends
Activity {
private
EditText et_name;
private
EditText et_pass;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_name = (EditText) findViewById(R.id.et_name);
et_pass = (EditText) findViewById(R.id.et_pass);
//拿到SharedPreferences对象
SharedPreferences sp = getSharedPreferences(
"info"
, MODE_PRIVATE);
//从SharedPreferences中取出数据
String name = sp.getString(
"name"
,
""
);
String pass = sp.getString(
"pass"
,
""
);
et_name.setText(name);
et_pass.setText(pass);
}
public
void
login(View v){
String name = et_name.getText().toString();
String pass = et_pass.getText().toString();
//拿到SharedPreferences对象
SharedPreferences sp = getSharedPreferences(
"info"
, MODE_PRIVATE);
//把数据存入SharedPreferences
Editor ed = sp.edit();
ed.putString(
"name"
, name);
ed.putString(
"pass"
, pass);
//提交
ed.commit();
}
}
|
2. Files 。
小案例:用户输入账号密码,勾选“记住账号密码”,点击登录按钮,登录的同时持久化保存账号和密码 。
•在内部存储空间中读写文件(RAM) 。
•布局文件:同上面的布局 。
•java代码: 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
package
com.bokeyuan.rwinrom;
import
java.io.BufferedReader;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.FileNotFoundException;
import
java.io.FileOutputStream;
import
java.io.InputStreamReader;
import
android.os.Bundle;
import
android.annotation.SuppressLint;
import
android.app.Activity;
import
android.content.Context;
import
android.view.Menu;
import
android.view.View;
import
android.widget.CheckBox;
import
android.widget.EditText;
import
android.widget.Toast;
public
class
MainActivity
extends
Activity {
private
EditText et_name;
private
EditText et_pass;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_name = (EditText) findViewById(R.id.et_name);
et_pass = (EditText) findViewById(R.id.et_pass);
readAccount();
}
@SuppressLint
(
"ShowToast"
)
public
void
login(View v){
String name = et_name.getText().toString();
String pass = et_pass.getText().toString();
CheckBox cb = (CheckBox) findViewById(R.id.cb);
if
(cb.isChecked()){
//指定Android的内部存储空间的路径
// File file = new File("data/data/com.bokeyuan.rwinrom/info.txt");
//返回一个File对象,它的路径是:data/data/com.bokeyuan.rwinrom/files/
// File file = new File(getFilesDir(), "info.txt");
//返回一个File对象,它的路径是:data/data/com.bokeyuan.rwinrom/cache/
File file =
new
File(getCacheDir(),
"info.txt"
);
try
{
FileOutputStream fos =
new
FileOutputStream(file);
fos.write((name +
"##"
+ pass).getBytes());
fos.close();
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//弹出提示框,提示用户登录成功
Toast.makeText(
this
,
"登陆成功"
,
0
).show();
}
public
void
readAccount(){
//指定Android的内部存储空间的路径
// File file = new File("data/data/com.bokeyuan.rwinrom/info.txt");
// File file = new File(getFilesDir(), "info.txt");
File file =
new
File(getCacheDir(),
"info.txt"
);
if
(file.exists()){
try
{
FileInputStream fis =
new
FileInputStream(file);
//把字节流转换成字符流
BufferedReader br =
new
BufferedReader(
new
InputStreamReader(fis));
String text = br.readLine();
String[] s = text.split(
"##"
);
et_name.setText(s[
0
]);
et_pass.setText(s[
1
]);
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
|
•在外部存储空间中读写文件(SD卡) 。
•布局文件:同上面的布局 。
•java代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
package
com.bokeyuan.rwinsd;
import
java.io.BufferedReader;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.FileNotFoundException;
import
java.io.FileOutputStream;
import
java.io.InputStreamReader;
import
com.bokeyuan.rwinsd.R;
import
android.os.Bundle;
import
android.os.Environment;
import
android.annotation.SuppressLint;
import
android.app.Activity;
import
android.content.Context;
import
android.view.Menu;
import
android.view.View;
import
android.widget.CheckBox;
import
android.widget.EditText;
import
android.widget.Toast;
public
class
MainActivity
extends
Activity {
private
EditText et_name;
private
EditText et_pass;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_name = (EditText) findViewById(R.id.et_name);
et_pass = (EditText) findViewById(R.id.et_pass);
readAccount();
}
public
void
login(View v){
String name = et_name.getText().toString();
String pass = et_pass.getText().toString();
CheckBox cb = (CheckBox) findViewById(R.id.cb);
if
(cb.isChecked()){
//检测sd卡当前是否可用
if
(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
// File file = new File("sdcard/info.txt");
//返回一个file对象,包含的路径就是sd卡的真实路径
File file =
new
File(Environment.getExternalStorageDirectory(),
"info.txt"
);
try
{
FileOutputStream fos =
new
FileOutputStream(file);
fos.write((name +
"##"
+ pass).getBytes());
fos.close();
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else
{
Toast.makeText(
this
,
"sd卡不可用哟亲"
,
0
).show();
}
}
//弹出提示框,提示用户登录成功
Toast.makeText(
this
,
"登陆成功"
,
0
).show();
}
public
void
readAccount(){
// File file = new File("sdcard/info.txt");
File file =
new
File(Environment.getExternalStorageDirectory(),
"info.txt"
);
if
(file.exists()){
try
{
FileInputStream fis =
new
FileInputStream(file);
//把字节流转换成字符流
BufferedReader br =
new
BufferedReader(
new
InputStreamReader(fis));
String text = br.readLine();
String[] s = text.split(
"##"
);
et_name.setText(s[
0
]);
et_pass.setText(s[
1
]);
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
|
注:
•//此api会把文件写到data/data/com.itheima.permission/files/文件夹下 •FileOutputStream fos = openFileOutput("info1.txt", MODE_PRIVATE) ; •//此api会把文件读到data/data/com.itheima.permission/files/文件夹下 •FileOutputStream fos = openFileOutput("info1.txt", MODE_PRIVATE) ,
•所以,以后用Android 自带的API。可以看下面openFileOutput四种模式的小例子:
•openFileOutput的四种模式 。
1
2
3
4
|
•MODE_PRIVATE =
0
: -rw-rw----
•MODE_APPEND =
32768
: -rw-rw----
•MODEWORLDREADABLE =
1
: -rw-rw-r--
•MODEWORLDWRITEABLE =
2
: -rw-rw--w-
|
Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中,可以使用Context.MODE_APPEND.
Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。 Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件。 MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入.
• 注:
•在Android中,每一个应用是一个独立的用户 •drwxrwxrwx •第1位:d表示文件夹,-表示文件 •第2-4位:rwx,表示这个文件的拥有者用户(owner)对该文件的权限 •r:读 •w:写 •x:执行 •第5-7位:rwx,表示跟文件拥有者用户同组的用户(grouper)对该文件的权限 •第8-10位:rwx,表示其他用户组的用户(other)对该文件的权限 。
•布局文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<LinearLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:paddingBottom=
"@dimen/activity_vertical_margin"
android:paddingLeft=
"@dimen/activity_horizontal_margin"
android:paddingRight=
"@dimen/activity_horizontal_margin"
android:paddingTop=
"@dimen/activity_vertical_margin"
tools:context=
".MainActivity"
android:orientation=
"vertical"
>
<Button
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
"创建文件1"
android:onClick=
"click1"
/>
<Button
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
"创建文件2"
android:onClick=
"click2"
/>
<Button
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
"创建文件3"
android:onClick=
"click3"
/>
</LinearLayout>
|
•代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
package
com.bokeyuan.permission;
import
java.io.File;
import
java.io.FileNotFoundException;
import
java.io.FileOutputStream;
import
android.os.Bundle;
import
android.annotation.SuppressLint;
import
android.app.Activity;
import
android.view.Menu;
import
android.view.View;
@SuppressLint
(
"WorldReadableFiles"
)
public
class
MainActivity
extends
Activity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public
void
click1(View v){
//此api会把文件写到data/data/com.bokeyuan.permission/files/文件夹下
try
{
FileOutputStream fos = openFileOutput(
"info1.txt"
, MODE_PRIVATE) ;
fos.write(
"该文件是私有数据,只能被应用本身访问"
.getBytes());
fos.close();
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public
void
click2(View v){
//此api会把文件写到data/data/com.bokeyuan.permission/files/文件夹下
try
{
@SuppressWarnings
(
"deprecation"
)
FileOutputStream fos = openFileOutput(
"info2.txt"
, MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE) ;
fos.write(
"当前文件可以被其他应用读取或写入"
.getBytes());
fos.close();
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public
void
click3(View v){
//此api会把文件写到data/data/com.bokeyuan.permission/files/文件夹下
try
{
@SuppressWarnings
(
"deprecation"
)
FileOutputStream fos = openFileOutput(
"info3.txt"
, MODE_WORLD_WRITEABLE) ;
fos.write(
"当前文件可以被其他应用写入"
.getBytes());
fos.close();
}
catch
(Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
|
•获取SD卡剩余容量:
•有时候读写文件的时候,需要判断SD卡的剩余容量,再进行写入操作。下面小例子,引用Android系统底层的API,获取SD卡的剩余容量.
•布局文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<RelativeLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:paddingBottom=
"@dimen/activity_vertical_margin"
android:paddingLeft=
"@dimen/activity_horizontal_margin"
android:paddingRight=
"@dimen/activity_horizontal_margin"
android:paddingTop=
"@dimen/activity_vertical_margin"
tools:context=
".MainActivity"
>
<TextView
android:id=
"@+id/tv"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
"@string/hello_world"
/>
</RelativeLayout>
|
•Java代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
package
com.bokeyuan.getsdavail;
import
java.io.File;
import
android.os.Build;
import
android.os.Bundle;
import
android.os.Environment;
import
android.os.StatFs;
import
android.app.Activity;
import
android.text.format.Formatter;
import
android.view.Menu;
import
android.widget.TextView;
public
class
MainActivity
extends
Activity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
File path = Environment.getExternalStorageDirectory();
StatFs stat =
new
StatFs(path.getPath());
long
blockSize;
long
totalBlocks;
long
availableBlocks;
//检测系统当前版本号
if
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){
blockSize = stat.getBlockSizeLong();
totalBlocks = stat.getBlockCountLong();
availableBlocks = stat.getAvailableBlocksLong();
}
else
{
blockSize = stat.getBlockSize();
totalBlocks = stat.getBlockCount();
availableBlocks = stat.getAvailableBlocks();
}
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(formatSize(availableBlocks * blockSize));
}
private
String formatSize(
long
size) {
return
Formatter.formatFileSize(
this
, size);
}
}
|
以上所述给大家介绍了Android开发笔记之Android中数据的存储方式(一)的相关知识,希望本文分享能够帮助到大家。下篇给android开发笔记之android中数据的存储方式(二),感兴趣的朋友点击了解详情.
最后此篇关于Android开发笔记之Android中数据的存储方式(一)的文章就讲到这里了,如果你想了解更多关于Android开发笔记之Android中数据的存储方式(一)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我一直在阅读有关汇编函数的内容,但对于是使用进入和退出还是仅使用调用/返回指令来快速执行,我感到很困惑。一种方式快而另一种方式更小吗?例如,在不内联函数的情况下,在汇编中执行此操作的最快(stdcal
我正在处理一个元组列表,如下所示: res = [('stori', 'JJ'), ('man', 'NN'), ('unnatur', 'JJ'), ('feel', 'NN'), ('pig',
最近我一直在做很多网络或 IO 绑定(bind)操作,使用线程有助于加快代码速度。我注意到我一直在一遍又一遍地编写这样的代码: threads = [] for machine, user, data
假设我有一个名为 user_stats 的资源,其中包含用户拥有的帖子、评论、喜欢和关注者的数量。是否有一种 RESTful 方式只询问该统计数据的一部分(即,对于 user_stats/3,请告诉我
我有一个简单的 api,它的工作原理是这样的: 用户创建一个请求 ( POST /requests ) 另一个用户检索所有请求 ( GET /requests ) 然后向请求添加报价 ( POST /
考虑以下 CDK Python 中的示例(对于这个问题,不需要 AWS 知识,这应该对基本上任何构建器模式都有效,我只是在这个示例中使用 CDK,因为我使用这个库遇到了这个问题。): from aws
Scala 中管理对象池的首选方法是什么? 我需要单线程创建和删除大规模对象(不需要同步)。在 C++ 中,我使用了静态对象数组。 在 Scala 中处理它的惯用和有效方法是什么? 最佳答案 我会把它
我有一个带有一些内置方法的类。这是该类的抽象示例: class Foo: def __init__(self): self.a = 0 self.b = 0
返回和检查方法执行的 Pythonic 方式 我目前在 python 代码中使用 golang 编码风格,决定移动 pythonic 方式 例子: import sys from typing imp
我正在开发一个 RESTful API。其中一个 URL 允许调用者通过 id 请求特定人员的记录。 返回该 id 不存在的记录的常规值是什么?服务器是否应该发回一个空对象或者一个 404,或者其他什
我正在使用 pathlib.Path() 检查文件是否存在,并使用 rasterio 将其作为图像打开. filename = pathlib.Path("./my_file-name.tif") 但
我正在寻找一种 Pythonic 方式来从列表和字典创建嵌套字典。以下两个语句产生相同的结果: a = [3, 4] b = {'a': 1, 'b': 2} c = dict(zip(b, a))
我有一个正在操裁剪理设备的脚本。设备有时会发生物理故障,当它发生时,我想重置设备并继续执行脚本。我有这个: while True: do_device_control() device
做组合别名的最pythonic和正确的方法是什么? 这是一个假设的场景: class House: def cleanup(self, arg1, arg2, kwarg1=False):
我正在开发一个小型客户端服务器程序来收集订单。我想以“REST(ful)方式”来做到这一点。 我想做的是: 收集所有订单行(产品和数量)并将完整订单发送到服务器 目前我看到有两种选择: 将每个订单行发
我知道在 Groovy 中您可以使用字符串调用类/对象上的方法。例如: Foo."get"(1) /* or */ String meth = "get" Foo."$meth"(1) 有没有办法
在 ECMAScript6 中,您可以使用扩展运算符来解构这样的对象 const {a, ...rest} = obj; 它将 obj 浅拷贝到 rest,不带属性 a。 有没有一种干净的方法可以在
我有几个函数返回数字或None。我希望我的包装函数返回第一个不是 None 的结果。除了下面的方法之外,还有其他方法吗? def func1(): return None def func2(
假设我想设计一个 REST api 来讨论歌曲、专辑和艺术家(实际上我就是这样做的,就像我之前的 1312414 个人一样)。 歌曲资源始终与其所属专辑相关联。相反,专辑资源与其包含的所有歌曲相关联。
这是我认为必须经常出现的问题,但我一直无法找到一个好的解决方案。假设我有一个函数,它可以作为参数传递一个开放资源(如文件或数据库连接对象),或者需要自己创建一个。如果函数需要自己打开文件,最佳实践通常
我是一名优秀的程序员,十分优秀!