Android 怎样在应用程序中向文件里写入数据?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 怎样在应用程序中向文件里写入数据?相关的知识,希望对你有一定的参考价值。
android 怎样在应用程序中向文件里写入数据?在AndroidManifest.xml中添加, <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />,解决!
另外了解一下android的数据存储方式:文件流的读取,SQLite,Content Provider以及Preference.。 注:resource和assets中的文件用户方面是只可以读取不能够进行写的操作的。
Content Provider作为程序之间唯一共享数据途径,用在这里不是很合适。所以,
第一种方式,使用FileInputStream,FileOutputStreamdui类实现文件I/O操作,直接往手机中存储数据。
第二种方式,使用SQLite,通过SQLiteDatabase类中方法操作数据。
第三种方式,Preference用于存储简单数据类型的数据,一些设置信息的保存。个人认为用在这里最合适。 它利用键值对存储的。例:
存储:SharedPreferences.Editor editor =sp.edit();
editor.putString(KEY_TEXT,"yonghu");
editor.commit();
获取 :sp =getPreferences(MODE_PRIVATE);
String result =sp.getString(KEY_TEXT,null)
Android保存数据几种常用方法解析
它应用于手机中能够帮助我们实现许多需求。比如今天为大家介绍的Android保存数据,就是其中一个比较重要的操作技巧。Android组件相关概念总结Android传值方法细讲Android横竖屏切换正确实现方式分享Android开发环境相关配置概览Android NDK具体作用讲解对于我们所熟悉的大部分软件都有一个比较典型的特点,应用现有的数据根据不同的需求来得到相应的结果。例如,我们最常用的Officeword、Excel、PowerPoint等办公软件,它们都是帮助我们完成某种特定的需求,同时由其所产生的数据或者文档又可以被其它软件所读取和做进一步的优化等等,在这个层面上可以看成是这些软件通过相同的文件标准来共享数据。但是对于Android最大的不同点在于,其平台上的应用软件所存储的数据或者文件是私有,仅仅可以通过它自身才可以访问其所包含的数据资源。那么基于这样的限制,该如何在Android平台上实现不同程序间的数据共享呢?答案非常简单 – 应用ContentProviders,这是建立在Android平台上用于定义统一的数据标准。Android提供了针对不同数据类型的ContentProviders来满足各种需要。例如:Image、Audio、Video和通讯录信息类等。阅读下边的文档之前,最好先熟悉Content Providers的概念。有了上边所提到Content Providers,接下来就要处理在共享文件过程中的存储环节了,这里有四种方法分别适用于不同情况的需求。它们都各自有相应的优缺点,所以当开发者决定选择应用哪种方法之前,先要考虑当前所操作的情况是否适合于所选择的方法。Preferences Files Databases Network 接下来将依次介绍上诉四个Android保存数据方法:Preferences从其保存数据的结构来分析,这是一个相对较轻量级的存储数据的方法。类似于我们常用的ini文件保存软件初始化设置,同样在Android平台常用于存储较简单的参数设置。例如,可以通过它保存上一次用户所作的修改或者自定义参数设定,当再次启动程序后依然保持原有的设置。通过Context.getSharedPreferences()方法来读写数值,这个方法通过设置name来使得同一个程序内的其它模块共享数据。如果不需要与其它模块共享数据,可以使用Activity.getPreferences()方法保持数据私有。需要着重强调一点,无法直接在多个程序间共享Preferences数据(不包括使用Content Providers)。通过一个实例来了解实际使用方法:import android.app.Activity; import android.content.SharedPreferences; public class Calc extends Activity public static final String PREFS_NAME = "MyPrefsFile"; . . . . Override protected void onCreate(Bundle state) super.onCreate(state); . . . . // Restore preferences SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); boolean silent = settings.getBoolean("silentMode", false); setSilent(silent); @Override protected void onStop() super.onStop(); // Save user preferences. We need an Editor object to // make changes. All objects are from android.context.Context SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); SharedPreferences.Editor editor = settings.edit(); editor.putBoolean("silentMode", mSilentMode); // Don't forget to commit your edits!!! editor.commit(); Files从这是第二种方法,可以在设备本身的存储设备或者外接的存储设备中创建用于保存数据的文件。同样在默认的状态下,文件是不能在不同的程序间共享。写文件:调用Context.openFileOutput()方法根据指定的路径和文件名来创建文件,这个方法会返回一个FileOutputStream对象。读取文件:调用Context.openFileInput()方法通过制定的路径和文件名来返回一个标准的Java FileInputStream对象。
(注意:在其它程序中将无法应用相同的路径和文件名来操作文件)另外编译程序之前,在res/raw/tempFile中建立一个static文件,这样可以在程序中通过Resources.openRawResource (R.raw.myDataFile)方法同样返回一个InputStream对象,直接读取文件内容。Databases在Android API中包括了应用SQLite databases的接口,每个程序所创建的数据库都是私有的,换句话说,程序间无法相互访问对方的数据库。在程序中创建SQLiteDatabase对象,其中包含了大部分与database交互的方法,例如:读取数据或者管理当前数据。可以应用SQLiteDatabase和其subClassSQLiteOpenHelper的create()方法来创建新的数据库。对于SQLitedatabase而言,其强大和方便的功能为Android提供了强有力的存储功能。特别是存储一些复杂的数据结构,例如:Android特别为通讯录创建了特有的数据类型,其中包含了非常多的子集而且涵盖了大部分的数据类型 “First Name” “Last Name” “PhoneNumber”和“Photo”等。Android可以通过Sqlite3 database tool来查看指定数据库中表的内容,直接运行SQL命令来快速便捷的直接操作SQLite database。
再加文件读写权限:
MODE_WORLD_READABLE, MODE_WORLD_WRITEABLE追问
这个权限怎么加?具体的实现方式是什么?
追答上次记错了.
其实是在AndroidManifest.xml中添加, ,
在 Dart 中向/从套接字数据写入/读取字节数
【中文标题】在 Dart 中向/从套接字数据写入/读取字节数【英文标题】:writing/reading number of bytes to/from socket data in Dart 【发布时间】:2015-05-18 19:44:02 【问题描述】:在以下服务器/客户端套接字代码中,服务器尝试发送从 0 到 1023 的整数。客户端接收到正确数量的整数,但它们在 255 处换行。为什么会这样,正确的方法是什么?
* 服务器 *
import 'dart:async';
import 'dart:io';
main() async
final server = await ServerSocket.bind('127.0.0.1', 4041);
server.listen((Socket socket)
print('Got connected $socket.remoteAddress');
for(int i=0; i<1024; i++)
socket.add([i]);
socket.close();
print('Closed $socket.remoteAddress');
);
* 客户端 *
import 'dart:async';
import 'dart:io';
main() async
final client = await Socket.connect('127.0.0.1', 4041);
client.listen(
(var data) => print('Got $data'),
onDone: () print('Done'); client.close(); ,
onError: (e) print('Got error $e'); client.close(); );
print('main done');
另外,感觉 Socket api 有点不同 - 它支持作为流读取的方式比其他语言更 Dartish。但是,如果您只想读取 N 个字节怎么办?你如何做到这一点?我看到了 take 方法(Stream take(int count)),但我不清楚 count 究竟采用了什么方法,尤其是在术语方面读取了多少字节。因为 Socket 实现了 Stream > 并且因为 int 并不是一个真正固定大小的实体(我想??),你怎么知道已经读取了多少字节?
【问题讨论】:
【参考方案1】:要明确的一点是,尽管dart:io
中的大多数方法都在List<int>
上运行,但 Dart 中所有 IO 的基本假设是这些列表是字节值列表。文档可能没有那么精确。
这意味着您可以在发送字节时使用您喜欢的任何 List
实现 - 包括类型化数据,例如
var socket = ...
socket.add([1, 2, 3]);
socket.add(new List<int>.generate(3, (int index) => index * index);
socket.add('ASCII'.codeUnits);
socket.add(UTF8.encode('Søren'));
var typedData = new Uint8List(8);
var data = new ByteData.view(typedData.buffer);
data.setInt32(0, 256 * 256 - 1);
data.setInt32(4, 256 * 256 - 1, Endianness.LITTLE_ENDIAN);
socket.add(typedData)
从套接字接收数据时,Socket
流上传递的数据是从操作系统传递的字节块。您无法预测当时接收到的字节数。如果您希望能够读取特定数量的字节,一个选项是实现一个字节读取器,它具有这样的方法:
Future<List<int>> read(int numBytes);
然后可以使用List<int>
流初始化此字节读取器并处理帧。您可以做的是有一个缓冲区(可能使用来自dart:io
的BytesBuilder
),它在接收到数据时收集数据。当read
被调用时,Future
在有足够的可用字节时完成。这样的字节读取器还可以在缓冲的数据量达到一定限制时暂停流,并在读取数据时再次恢复。
【讨论】:
【参考方案2】:这对我有用,我不确定这是最优雅的解决方案
import 'dart:io';
import 'dart:async';
import 'dart:typed_data';
main() async
final server = await ServerSocket.bind('127.0.0.1', 4041);
server.listen((Socket socket)
print('Got connected $socket.remoteAddress');
var toByte = new StreamTransformer<List<int>, Uint8List>.fromHandlers(
handleData: (data, sink)
sink.add(new Uint64List.fromList(data).buffer.asUint8List());
);
var streamController = new StreamController<List<int>>();
streamController.stream.transform(toByte).pipe(socket);
for (int i = 0; i < 1024; i++)
streamController.add([i]);
streamController.close();
print('Closed $socket.remoteAddress');
);
import 'dart:io';
import 'dart:async';
main() async
final Socket client = await Socket.connect('127.0.0.1', 4041);
var fromByte = new StreamTransformer<List<int>, List<int>>.fromHandlers(
handleData: (data, sink)
sink.add(data.buffer.asInt64List());
);
client.transform(fromByte).listen((e) => e.forEach(print));
print('main done');
最初的尝试:
import 'dart:io';
import 'dart:typed_data';
main() async
final server = await ServerSocket.bind('127.0.0.1', 4041);
server.listen((Socket socket)
print('Got connected $socket.remoteAddress');
for(int i=0; i<1024; i++)
socket.add(new Uint64List.fromList([i]).buffer.asUint8List());
socket.close();
print('Closed $socket.remoteAddress');
);
import 'dart:io';
import 'dart:typed_data';
main() async
final Socket client = await Socket.connect('127.0.0.1', 4041);
client.listen(
(var data)
var ints = new Uint8List.fromList(data).buffer.asInt64List();
ints.forEach((i) => print('Got $i'));
,
onDone: () print('Done'); client.close(); ,
onError: (e) print('Got error $e'); client.close(); );
print('main done');
如果您不需要 Int64 的范围,您也可以使用 Int32、Int16 或某些 UIntXX 类型或任何最适合您的值范围的类型,以节省一些冗余传输的 0 字节。
我怀疑使用这里解释的转换器https://www.dartlang.org/articles/converters-and-codecs/ 可以用来更优雅地完成它。这似乎与https://gist.github.com/xxgreg/9104926 相似,但我不得不承认我无法将这些示例应用于您的用例。
更新
我让它像上面链接的文章中显示的那样工作
import 'dart:convert';
import 'dart:typed_data';
class IntConverter extends Converter<List<int>, List<int>>
const IntConverter();
List<int> convert(List<int> data)
if (data is Uint8List)
return data.buffer.asInt64List();
else
return new Uint64List.fromList(data).buffer.asUint8List();
IntSink startChunkedConversion(sink)
return new IntSink(sink);
class IntSink extends ChunkedConversionSink<List<int>>
final _converter;
// fales when this type is used
// final ChunkedConversionSink<List<int>> _outSink;
final _outSink;
IntSink(this._outSink) : _converter = new IntConverter();
void add(List<int> data)
_outSink.add(_converter.convert(data));
void close()
_outSink.close();
import 'dart:io';
import 'dart:typed_data';
main() async
final server = await ServerSocket.bind('127.0.0.1', 4041);
server.listen((Socket socket)
print('Got connected $socket.remoteAddress');
for (int i = 0; i < 1024; i++)
socket.add(new Uint64List.fromList([i]).buffer.asUint8List());
socket.close();
print('Closed $socket.remoteAddress');
);
import 'dart:io';
import 'byte_converter.dart';
main() async
final Socket client = await Socket.connect('127.0.0.1', 4041);
client.transform(new IntConverter()).listen((e) => e.forEach(print));
print('main done');
【讨论】:
谢谢甘特。我想一个基本的后续行动是为什么让套接字实现像 Stream> 这样的东西,因为不清楚发生了什么,因为 int 有一个层次结构。但是 Stream 很明显,它将它留给更高层来解释一些字节数。另外,你如何从套接字中读取 n 个字节?似乎缓冲是固有的,从日志记录中我看到数据中的元素数量是不确定的。 我想应该是Stream<Uint8List>
明确并避免歧义。希望当他看到这个问题时,我们可以从 LRHN 那里得到一些额外的信息。
Uint8List 在 dart:typed_data 中,我猜不想在 dart:io 中引入依赖项。如果 Dart 完全实现了 typedef,那么就可以“typedef byte int;”,然后它就会变成一个 Stream>。我有点喜欢 Streams 和 Lists 的可组合性,所以我不确定我是否喜欢“typedef ByteStream Stream>;”,这将是另一种方式。
@GünterZöchbauer - 假设传递给 IntConverter.convert() 的块总是 8 的倍数是否安全?
数字被转换为二进制并通过网络发送。网络层将二进制文件拆分为任意大小的数据包,然后接收软件从网络层获取数据包,其大小取决于操作系统的网络实现。如果网络决定将数据分割成大小为 1500 字节(不是 8 的倍数)的数据包,会发生什么?您将在一个数据包中获得一半 int64,然后在下一个数据包中获得另一半。您的 IntConverter 类没有正确处理这个问题。以上是关于Android 怎样在应用程序中向文件里写入数据?的主要内容,如果未能解决你的问题,请参考以下文章