I want to delete file in Directory.
It is created like so.
final Directory extDir = await getTemporaryDirectory();
final String dirPath = '${extDir.path}/video';
await new Directory(dirPath).create(recursive: true);
final String filePath = '$dirPath/${timestamp()}.mp4';
I want to delete this specific path so that app won't heavy.
How can I do this?
Does anyone have an idea?
You don't need to move to the directory. You pass the path to the Directory constructor:
import 'dart:io';
void main() {
final dir = Directory(dirPath);
dir.deleteSync(recursive: true);
}
Related
In nodejs I simply use path
import path from "path";
path.resolve(__dirname, '../', './test.txt');
Is there any way to use in dart ?
import 'package:path/path.dart' as path;
void main(List<String> args) {
final relative = 'example/example.dart';
final absolute = path.normalize(path.absolute(relative));
print(absolute);
final dir = path.dirname(absolute);
print(dir);
final absolute2 =
path.normalize(path.absolute(path.join(dir, '../', './test.txt')));
print(absolute2);
}
Output (in my case):
E:\prj\dart_test\example\example.dart
E:\prj\dart_test\example
E:\prj\dart_test\test.txt
P.S.
I prefer to use normalize but this is matter of taste.
You probably want to use File.absolute.path/Directory.absolute.path.
The two pages in the application are listed with database(sqlite). but when I want to switch between pages, I get such an error: SqfliteDatabaseException (DatabaseException(database_closed))
please help mee.. I don't understand why see this error.
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:bankingapp/models/coin.dart';
import 'package:bankingapp/models/histories.dart';
import 'package:flutter/services.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DbHelper {
static Database? _db;
Future<Database> get db async {
return _db ??= await initDb();
}
Future<Database> initDb() async {
var dbFolder = await getDatabasesPath();
String path = join(dbFolder, 'app.db');
// Delete any existing database:
await deleteDatabase(path);
// Create the writable database file from the bundled demo database file:
try {
await Directory(dirname(path)).create(recursive: true);
} catch (_) {}
ByteData data =
await rootBundle.load(join("assets/database", "bankingapp.db"));
List<int> bytes =
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
await new File(path).writeAsBytes(bytes, flush: true);
//open the database
return await openDatabase(path);
/*
var dbFolder = await getDatabasesPath();
String path = join(dbFolder, 'app.db');
return await openDatabase(path);*/
}
Future<List<Histories>> getHistories() async {
var dbClient = await db;
var result = await dbClient.rawQuery("SELECT * FROM Histories");
return result.map((data) => Histories.fromMap(data)).toList();
}
Future<List<Coins>> getCoins() async {
var dbClient = await db;
var result = await dbClient.rawQuery("SELECT * FROM Coins");
return result.map((data) => Coins.fromMap(data)).toList();
}
}
First, uninstall the app from the device and run flutter clean and then build a new app and run it again to see if the error occurs.
Then, check the device in which you are running your app has restricted your app or not, see if your device requires any particular permission.
If it still occurs according to your provided information it seems like the problem is either the database is getting closed or it's not opening it can be because of many reasons like not doing proper initialization or even just forgetting to put await. Check the database initialization code in which you are opening your database or not then check if you are by mistake closing the database somewhere, which should have been done only when the app is terminated.
If you have done both of the above steps correct check your database location and mapping.
If nothing is working please try to follow official sqflite docs and example, as your code seems different from the one shown in the plugin example.
I'm trying to handle file upload through multipart requests with Aqueduct. Aqueduct has now an example on how to handle multipart requests here:
https://aqueduct.io/docs/http/request_and_response/#example-multipartform-data
The example explains, how to get the header and the content of the files. However it doesn't explain how to write the content into a file on disk.
How can I write the content of the files uploaded to disk?
Below an example that shows what I want to achieve, but doesn't work:
import 'dart:io';
import 'package:aqueduct/aqueduct.dart';
import 'package:mime/mime.dart';
class MediaUploadController extends ResourceController {
MediaUploadController() {
acceptedContentTypes = [ContentType("multipart", "form-data")];
}
#Operation.post()
Future<Response> postMultipartForm() async {
final transformer = MimeMultipartTransformer(request.raw.headers.contentType.parameters["boundary"]);
final bodyStream = Stream.fromIterable([await request.body.decode<List<int>>()]);
final parts = await transformer.bind(bodyStream).toList();
for (var part in parts) {
final String contentType = part.headers["content-type"];
// Write content to disk
final content = await part.toList();
final fileName = DateTime.now().millisecondsSinceEpoch.toString() + ".jpg";
var file = new File('data/' + fileName);
var sink = file.openWrite();
sink.write(content);
sink.close();
}
return new Response.ok({});
}
}
This below actually worked. Additionally to the mime package, I have also added the http_server package to pubspec.yaml, because it makes it easier to handle the multipart form data.
dependencies:
aqueduct: ^3.0.1
mime: ^0.9.6+2
http_server: ^0.9.8+1
Then I studied some other frameworks to see how they handled writing to the file. It's so complicated to get how this multipart stuff and streams work together. But at last after nearly a week, the light at the end of the tunnel... until the next questions pop up. Most likely 10 minutes down the line :)
import 'dart:io';
import 'package:aqueduct/aqueduct.dart';
import 'package:mime/mime.dart';
import 'package:http_server/http_server.dart';
class MediaUploadController extends ResourceController {
MediaUploadController() {
acceptedContentTypes = [ContentType("multipart", "form-data")];
}
#Operation.post()
Future<Response> postMultipartForm() async {
final transformer = MimeMultipartTransformer(request.raw.headers.contentType.parameters["boundary"]);
final bodyStream = Stream.fromIterable([await request.body.decode<List<int>>()]);
final parts = await transformer.bind(bodyStream).toList();
for (var part in parts) {
HttpMultipartFormData multipart = HttpMultipartFormData.parse(part);
final ContentType contentType = multipart.contentType;
final content = multipart.cast<List<int>>();
final filePath = "data/" + DateTime.now().millisecondsSinceEpoch.toString() + ".jpg";
IOSink sink = File(filePath).openWrite();
await for (List<int> item in content) {
sink.add(item);
}
await sink.flush();
await sink.close();
}
return new Response.ok({});
}
}
from the flutter doc:
class CounterStorage {
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/counter.txt');
}
Future<int> readCounter() async {
try {
final file = await _localFile;
// Read the file
String contents = await file.readAsString();
return int.parse(contents);
} catch (e) {
// If we encounter an error, return 0
return 0;
}
}
Future<File> writeCounter(int counter) async {
final file = await _localFile;
// Write the file
return file.writeAsString('$counter');
}
}
Both readCounter() and writeCounter() call the _localPath getter each time they're called.
My question is :
isn't this a little wasteful? Wouldn't it be better to wait for the _localFile in the constructor of CounterStorage, and store it in a class member, as opposed to getting the _localPath and _localPath each and every time?
Can someone please suggest such an implementation?
It depends what you mean by wasteful, and the contract of getApplicationDocumentsDirectory.
For example, if it is possible for getApplicationDocumentsDirectory() to return a different path the next time it is called (for example, if a new user logs in, possibly - I'm not sure of the details) then this is completely correct.
If it is guaranteed this value will never change, it is possible to optimize further, but showing optimizations is probably not the goal of sample documentation. If you're interested, two ideas I can think of are:
Create a static final field:
class CounterStorage {
// Static fields in Dart are lazy; this won't get sent until used.
static final _localPath = getApplicationDocumentsDirectory().then((p) => p.path);
// ...
}
This is my preference if CounterStorage has other methods or fields that are uesful without waiting for _localPath to be resolved. In the above example, there are none, so I would prefer:
Create a static async method to create CounterStorage
import 'package:meta/meta.dart';
class CounterStorage {
// You could even combine this with the above example, and make this a
// static final field.
static Future<CounterStorage> resolve() async {
final localPath = await getApplicationDocumentsDirectory();
return new CounterStorage(new File(this.localPath));
}
final File _file;
// In a test you might want to use a temporary directory instead.
#visibleForTesting
CounterStorage(this._file);
Future<int> readCount() async {
try {
final contents = await _file.readAsString();
return int.parse(contents);
} catch (_) {
return 0;
}
}
}
This makes the process of retrieving the File happen potentially once per app.
I have a list of models that I need to create a mini reflective system.
I analyzed the Serializable package and understood how to create one generated file per file, however, I couldn't find how can I create one file for a bulk of files.
So, how to dynamically generate one file, using source_gen, for a list of files?
Example:
Files
user.dart
category.dart
Generated:
info.dart (containg information from user.dart and category.dart)
Found out how to do it with the help of people in Gitter.
You must have one file, even if empty, to call the generator. In my example, it is lib/batch.dart.
source_gen: ^0.5.8
Here is the working code:
The tool/build.dart
import 'package:build_runner/build_runner.dart';
import 'package:raoni_global/phase.dart';
main() async {
PhaseGroup pg = new PhaseGroup()
..addPhase(batchModelablePhase(const ['lib/batch.dart']));
await build(pg,
deleteFilesByDefault: true);
}
The phase:
batchModelablePhase([Iterable<String> globs =
const ['bin/**.dart', 'web/**.dart', 'lib/**.dart']]) {
return new Phase()
..addAction(
new GeneratorBuilder(const
[const BatchGenerator()], isStandalone: true
),
new InputSet(new PackageGraph.forThisPackage().root.name, globs));
}
The generator:
import 'dart:async';
import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
import 'package:glob/glob.dart';
import 'package:build_runner/build_runner.dart';
class BatchGenerator extends Generator {
final String path;
const BatchGenerator({this.path: 'lib/models/*.dart'});
#override
Future<String> generate(Element element, BuildStep buildStep) async {
// this makes sure we parse one time only
if (element is! LibraryElement)
return null;
String libraryName = 'raoni_global', filePath = 'lib/src/model.dart';
String className = 'Modelable';
// find the files at the path designed
var l = buildStep.findAssets(new Glob(path));
// get the type of annotation that we will use to search classes
var resolver = await buildStep.resolver;
var assetWithAnnotationClass = new AssetId(libraryName, filePath);
var annotationLibrary = resolver.getLibrary(assetWithAnnotationClass);
var exposed = annotationLibrary.getType(className).type;
// the caller library' name
String libName = new PackageGraph.forThisPackage().root.name;
await Future.forEach(l.toList(), (AssetId aid) async {
LibraryElement lib;
try {
lib = resolver.getLibrary(aid);
} catch (e) {}
if (lib != null && Utils.isNotEmpty(lib.name)) {
// all objects within the file
lib.units.forEach((CompilationUnitElement unit) {
// only the types, not methods
unit.types.forEach((ClassElement el) {
// only the ones annotated
if (el.metadata.any((ElementAnnotation ea) =>
ea.computeConstantValue().type == exposed)) {
// use it
}
});
});
}
});
return '''
$libName
''';
}
}
It seems what you want is what this issue is about How to generate one output from many inputs (aggregate builder)?
[Günter]'s answer helped me somewhat.
Buried in that thread is another thread which links to a good example of an aggregating builder:
1https://github.com/matanlurey/build/blob/147083da9b6a6c70c46eb910a3e046239a2a0a6e/docs/writing_an_aggregate_builder.md
The gist is this:
import 'package:build/build.dart';
import 'package:glob/glob.dart';
class AggregatingBuilder implements Builder {
/// Glob of all input files
static final inputFiles = new Glob('lib/**');
#override
Map<String, List<String>> get buildExtensions {
/// '$lib$' is a synthetic input that is used to
/// force the builder to build only once.
return const {'\$lib$': const ['all_files.txt']};
}
#override
Future<void> build(BuildStep buildStep) async {
/// Do some operation on the files
final files = <String>[];
await for (final input in buildStep.findAssets(inputFiles)) {
files.add(input.path);
}
String fileContent = files.join('\n');
/// Write to the file
final outputFile = AssetId(buildStep.inputId.package,'lib/all_files.txt');
return buildStep.writeAsString(outputFile, fileContent);
}
}