![](/img/trans.png)
[英]Best way to save large text data (hold in a stringbuilder) in SQL Database?
[英]Best way to save and read large files?
我正在嘗試為移動 + Windows 系統創建一個白標流媒體/雲文件管理工具。 目標是能夠查看遠程內容並使用充當文件“代理”的應用程序下載它——只有應用程序可以打開它們,下載時它會在本地加密和保存數據。 目前我已經嘗試過Hive SQLite3 ,現在我正在從頭開始Isar 。
以上解決方案均不適用於超過 2GB 的文件。 Hive 需要 7 分鍾來保存和加密 3GB 數據塊。 更糟糕的是,保存的文件總計超過 9GB。 SQLite 在 3.5 分鍾時做得更好,同時還減小了最終文件的大小,但這似乎也是一個太長的過程。
另一件事是在加密和保存數據處理器時,memory 和 Windows 機器上的磁盤使用率始終為 99%。 我不想想象這個過程會對 2017 年的手機造成多大的影響。
試試這段代碼(它使用blowfish_ecb加密算法,但也可以使用任何其他算法),注意解密時我們不必包裝原始 stream 並直接使用它( return (encrypt? makeBigChunksAndPadZeros(inStream, inStreamLength, outMap): inStream)
)
class FooWidget1 extends StatefulWidget {
@override
State<FooWidget1> createState() => _FooWidget1State();
}
class _FooWidget1State extends State<FooWidget1> {
final notifier = ValueNotifier(0.0);
Duration timeSpan = Duration.zero;
Map<String, dynamic> out = {};
String status = '';
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.topCenter,
child: Column(
children: [
ElevatedButton(
onPressed: () async {
final start = DateTime.now();
int length;
File inFile;
File outFile;
// case 1: encrypting from network
// final uri = Uri.parse('http://0.0.0.0:8000/open.mp4');
// final response = await http.Request('get', uri).send();
// // print(response.headers);
// length = response.contentLength!;
// outFile = File('secret.file');
// setState(() {
// status = 'encrypting\n\nsrc: [$uri]\ndst: [$outFile]\nlength: $length bytes';
// });
// out = await crypt(
// encrypt: true,
// key: 'foo bar key',
// inStream: response.stream,
// inStreamLength: length,
// outFile: outFile,
// notifier: notifier,
// );
// end of case 1
// case 2: encrypting from file
// inFile = File('open.mp4');
// length = await inFile.length();
// outFile = File('secret.file');
// setState(() {
// status = 'encrypting\n\nsrc: [$inFile]\ndst: [$outFile]\nlength: $length bytes';
// });
// out = await crypt(
// encrypt: true,
// key: 'foo bar key',
// inStream: inFile.openRead(),
// inStreamLength: length,
// outFile: outFile,
// notifier: notifier,
// );
// end of case 2
// case 3: decrypting from file
inFile = File('secret.file');
length = await inFile.length();
outFile = File('open1.mp4');
setState(() {
status = 'decrypting\n\nsrc: [$inFile]\ndst: [$outFile]\nlength: $length bytes';
});
out = await crypt(
encrypt: false,
key: 'foo bar key',
inStream: inFile.openRead(),
inStreamLength: length,
outFile: outFile,
notifier: notifier,
pad: 7,
);
// end of case 3
timeSpan = DateTime.now().difference(start);
setState(() {
status = status + '\n\ntook: ${timeSpan.inMilliseconds / 1000}s\npad: ${out['pad']}';
});
},
child: const Text('start crypting'),
),
SizedBox.fromSize(
size: const Size.square(100),
child: Padding(
padding: const EdgeInsets.all(8),
child: AnimatedBuilder(
animation: notifier,
builder: (ctx, child) => CircularProgressIndicator(value: notifier.value),
),
),
),
Text(status, textScaleFactor: 1.5),
],
),
);
}
Future<Map<String, dynamic>> crypt({
bool encrypt = true,
required String key,
required Stream<List<int>> inStream,
required int inStreamLength,
required File outFile,
ValueNotifier<double>? notifier,
int pad = 0,
}) async {
int readBytes = 0;
double oldValue = 0;
// it needs: import 'package:blowfish_ecb/blowfish_ecb.dart';
final blowfishECB = BlowfishECB(Uint8List.fromList(utf8.encode(key)));
List<int> mapper(List<int> data) {
if (notifier != null && inStreamLength > 0) {
readBytes += data.length;
final currentValue = readBytes / inStreamLength;
if (currentValue > oldValue + 0.01) {
oldValue = currentValue;
notifier.value = currentValue;
}
}
if (encrypt) {
data = blowfishECB.encode(data);
} else {
data = blowfishECB.decode(data);
if (readBytes == inStreamLength && pad != 0) {
// the last chunk with non zero [pad]
print('crypt: removing $pad byte(s)');
data = data.sublist(0, data.length - pad);
}
}
return data;
}
final outMap = {
'size': 0,
'pad': 0,
};
return (encrypt? makeBigChunksAndPadZeros(inStream, inStreamLength, outMap) : inStream)
.map(mapper)
.pipe(outFile.openWrite())
.then((value) => outMap..['size'] = readBytes);
}
Stream<List<int>> makeBigChunksAndPadZeros(Stream<List<int>> inStream, int inStreamLength, Map outMap) async* {
// TODO make it bigger / smaller
const chunkSize = 1 * 1024 * 1024;
int index = 0;
final reader = ChunkedStreamReader(inStream);
while (true) {
var chunk = await reader.readChunk(chunkSize);
index += chunk.length;
if (index != inStreamLength) {
// normal chunk
yield chunk;
} else {
// the last chunk
if (chunk.isNotEmpty) {
// not empty chunk: add zeroes if needed
final pad = 8 - chunk.length % 8;
if (pad != 8) {
print('makeBigChunksAndPadZeros: adding $pad zero(s)');
chunk = List.of(chunk.followedBy(List.filled(pad, 0)));
outMap['pad'] = pad;
}
yield chunk;
}
break;
}
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.