diff --git a/README.md b/README.md
index cb1ff60faee39c3cefc00215086c4cbd4bd29c7b..bce04add25360f754742d39413e3665bb64a536e 100644
--- a/README.md
+++ b/README.md
@@ -9,9 +9,9 @@ Created from templates made available by Stagehand under a BSD-style
 |-----------------------	|------------------------	|----------------------	|-----------------------------------------	|
 | `makeBucket`           	| `getObject`            	| presignedUrl         	| getBucketNotification                   	|
 | `listBuckets`          	| `getPartialObject`     	| presignedGetObject   	| setBucketNotification                   	|
-| `bucketExists`         	| fGetObject             	| presignedPutObject   	| removeAllBucketNotification             	|
+| `bucketExists`         	| `fGetObject`           	| presignedPutObject   	| removeAllBucketNotification             	|
 | `removeBucket`         	| `putObject`            	| presignedPostPolicy  	| getBucketPolicy                         	|
-| `listObjects`          	| fPutObject             	|                      	| setBucketPolicy                         	|
+| `listObjects`          	| `fPutObject`           	|                      	| setBucketPolicy                         	|
 | `listObjectsV2`        	| `copyObject`           	|                      	| listenBucketNotification                	|
 | `listIncompleteUploads`	| `statObject`           	|                      	|                                         	|
 |                       	| `removeObject`         	|                      	|                                         	|
diff --git a/example/custed.png b/example/custed.png
new file mode 100644
index 0000000000000000000000000000000000000000..fb7f4c21e83607b8a2acb1e94c374c4c5c4b064b
Binary files /dev/null and b/example/custed.png differ
diff --git a/example/minio_example.dart b/example/minio_example.dart
index 882c39705574b3102295829b73706c61c4f81d11..dcf4563d4938c1e7e746b082903aa6ce58b0a2de 100644
--- a/example/minio_example.dart
+++ b/example/minio_example.dart
@@ -1,5 +1,4 @@
-import 'dart:io';
-
+import 'package:minio/io.dart';
 import 'package:minio/minio.dart';
 
 void main() async {
@@ -12,9 +11,9 @@ void main() async {
   );
 
   final bucket = '00test';
-  final object = 'teaweb.png';
-  final copy1 = '$object.copy1';
-  final copy2 = '$object.copy2';
+  final object = 'custed.png';
+  final copy1 = 'custed.copy1.png';
+  final copy2 = 'custed.copy2.png';
 
   if (!await minio.bucketExists(bucket)) {
     await minio.makeBucket(bucket);
@@ -27,9 +26,7 @@ void main() async {
   print('--- object region:');
   print(region);
 
-  final file = File('example/$object');
-  final size = await file.length();
-  final etag = await minio.putObject(bucket, object, file.openRead(), size);
+  final etag = await minio.fPutObject(bucket, object, 'example/$object');
   print('--- etag:');
   print(etag);
 
@@ -40,6 +37,9 @@ void main() async {
   print('--- copy2 etag:');
   print(copyResult2.eTag);
 
+  await minio.fGetObject(bucket, object, 'example/$copy1');
+  print('--- copy1 downloaded');
+
   await minio.listObjects(bucket).forEach((chunk) {
     print('--- objects:');
     chunk.objects.forEach((o) => print(o.key));
diff --git a/example/teaweb.png b/example/teaweb.png
deleted file mode 100644
index 84746b3b671c92a99bfe0bb17c9abd2a66b24ac6..0000000000000000000000000000000000000000
Binary files a/example/teaweb.png and /dev/null differ
diff --git a/lib/io.dart b/lib/io.dart
new file mode 100644
index 0000000000000000000000000000000000000000..26f5ebf3fa63fa71c1c7111dff8c43a2657a1cb5
--- /dev/null
+++ b/lib/io.dart
@@ -0,0 +1,71 @@
+import 'dart:io';
+
+import 'package:minio/src/minio.dart';
+import 'package:minio/src/minio_errors.dart';
+import 'package:minio/src/minio_helpers.dart';
+import 'package:path/path.dart' show dirname;
+
+extension MinioX on Minio {
+  Future<String> fPutObject(
+    String bucket,
+    String object,
+    String filePath, [
+    Map<String, String> metaData,
+  ]) async {
+    MinioInvalidBucketNameError.check(bucket);
+    MinioInvalidObjectNameError.check(object);
+
+    metaData ??= {};
+    metaData = insertContentType(metaData, filePath);
+    metaData = prependXAMZMeta(metaData);
+
+    final file = File(filePath);
+    final stat = await file.stat();
+    if (stat.size > maxObjectSize) {
+      throw MinioError(
+        '${filePath} size : ${stat.size}, max allowed size : 5TB',
+      );
+    }
+
+    return putObject(bucket, object, file.openRead(), stat.size);
+  }
+
+  Future<void> fGetObject(
+    String bucket,
+    String object,
+    String filePath,
+  ) async {
+    MinioInvalidBucketNameError.check(bucket);
+    MinioInvalidObjectNameError.check(object);
+
+    final stat = await statObject(bucket, object);
+    final dir = dirname(filePath);
+    await Directory(dir).create(recursive: true);
+
+    final partFileName = '${filePath}.${stat.etag}.part.minio';
+    final partFile = File(partFileName);
+    IOSink partFileStream;
+    var offset = 0;
+
+    final rename = () => partFile.rename(filePath);
+
+    if (await partFile.exists()) {
+      final localStat = await partFile.stat();
+      if (stat.size == localStat.size) return rename();
+      offset = localStat.size;
+      partFileStream = partFile.openWrite(mode: FileMode.append);
+    } else {
+      partFileStream = partFile.openWrite(mode: FileMode.write);
+    }
+
+    final dataStream = await getPartialObject(bucket, object, offset);
+    await dataStream.pipe(partFileStream);
+
+    final localStat = await partFile.stat();
+    if (localStat.size != stat.size) {
+      throw MinioError('Size mismatch between downloaded file and the object');
+    }
+
+    return rename();
+  }
+}
diff --git a/lib/src/minio.dart b/lib/src/minio.dart
index d3551de3fb2b1a6b65a6b1e4f3438dbafce54bec..787e13d85789786596e50720b838701035269627 100644
--- a/lib/src/minio.dart
+++ b/lib/src/minio.dart
@@ -382,7 +382,7 @@ class Minio {
 
     return latestUpload?.uploadId;
   }
-
+  
   Future<String> getBucketRegion(String bucket) async {
     MinioInvalidBucketNameError.check(bucket);
 
diff --git a/lib/src/minio_helpers.dart b/lib/src/minio_helpers.dart
index c0e7277fe4d7cfe2f4bbec054d7ded09ceafb19e..5c0bf5457790a99f2981d3d80c14fbe764d8d3cf 100644
--- a/lib/src/minio_helpers.dart
+++ b/lib/src/minio_helpers.dart
@@ -1,3 +1,5 @@
+import 'package:mime/mime.dart' show lookupMimeType;
+
 bool isValidBucketName(String bucket) {
   if (bucket == null) return false;
 
@@ -170,3 +172,23 @@ Map<String, String> extractMetadata(Map<String, String> metaData) {
   }
   return newMetadata;
 }
+
+String probeContentType(String path) {
+  final contentType = lookupMimeType(path);
+  return contentType ?? 'application/octet-stream';
+}
+
+Map<String, String> insertContentType(
+  Map<String, String> metaData,
+  String filePath,
+) {
+  for (var key in metaData.keys) {
+    if (key.toLowerCase() == 'content-type') {
+      return metaData;
+    }
+  }
+
+  final newMetadata = Map<String, String>.from(metaData);
+  newMetadata['content-type'] = probeContentType(filePath);
+  return newMetadata;
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index cccb17125ce0e026b63f86a9dd5e3dba80daf084..3bd02a1d1c6da1168e40b85f0da540a0150db926 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -5,7 +5,7 @@ version: 0.1.0
 author: xuty <root@xuty.tk>
 
 environment:
-  sdk: ">=2.5.0 <3.0.0"
+  sdk: ">=2.7.0 <3.0.0"
 
 dependencies:
   meta: ^1.1.7
@@ -15,7 +15,8 @@ dependencies:
   xml: ^3.7.0
   buffer: ^1.0.6
   intl: ^0.16.1
-#  path: ^1.6.0
+  mime: ^0.9.6+3
+  path: ^1.6.0
 
 dev_dependencies:
   pedantic: ^1.8.0