Herbert Yu
Herbert Yu

Reputation: 578

How to read files on Android phone from C# program on Windows 7?

When I connect my Android phone to my Windows 7 with USB cable, Windows pop-up a window and show me the phone's internal storage at Computer\HTC VLE_U\Internal storage from Windows Explorer. But there is no drive letter linked with this phone storage! Inside Windows Explorer, I can manipulate the file system.

How can I manipulate the same files or folders from C# program?

As I tested,

DirectoryInfo di = new DirectoryInfo(@"C:\"); 

works, but

DirectoryInfo di = new DirectoryInfo(@"Computer\HTC VLE_U\Internal storage");

failed.

But in Windows Explorer, IT IS Computer\HTC VLE_U\Internal storage! No drive letter!

Yes, this is MTP device.

I see this answer in Stack Overflow, but the return results are empty for me after running this code

var drives = DriveInfo.GetDrives();
var removableFatDrives = drives.Where(
    c=>c.DriveType == DriveType.Removable &&
    c.DriveFormat == "FAT" && 
    c.IsReady);
var androids = from c in removableFatDrives
    from d in c.RootDirectory.EnumerateDirectories()
    where d.Name.Contains("android")
    select c;

I get correct drives. But android phone's internal storage is not here. Both removableFatDrives and androids are empty for me.

Upvotes: 13

Views: 7845

Answers (2)

Ji_in_coding
Ji_in_coding

Reputation: 1701

Using ZackOfAllTrades' code, I ran into OutOfMemoryException when invoking MediaDevice.DownloadFile(string, Stream).

[1] Go to project properties, set project to build for x64, that seems to get rid of OutOfMemoryException; I am able to start copying files between 1GB to 2GB without any problems.

[2] However, as soon as I start copying files of 2.5GB the WriteStreamToDisk() util function by ZackOfAllTrades started to complain about Stream too long.

DownloadFile takes a Stream object, it doesn't need to be a MemoryStream so I switched it to a FileStream object :

static void Main(string[] args)
{
    string DeviceNameAsSeenInMyComputer = "Mi Note 10 Pro";

    var devices = MediaDevice.GetDevices();

    using (var device = devices.Where(d => d.FriendlyName == DeviceNameAsSeenInMyComputer || d.Description == DeviceNameAsSeenInMyComputer).First())
    {
        device.Connect();
        var photoDir = device.GetDirectoryInfo(@"\Internal shared storage\DCIM\Camera");
        var files = photoDir.EnumerateFiles("*.*", SearchOption.TopDirectoryOnly);

        foreach (var file in files)
        {
            string destinationFileName = $@"F:\Photo\{file.Name}";
            if (!File.Exists(destinationFileName))
            {
                using (FileStream fs = new FileStream(destinationFileName, FileMode.Create, System.IO.FileAccess.Write))
                {
                    device.DownloadFile(file.FullName, fs);
                }
            }

            
        }
        device.Disconnect();
    }

    Console.WriteLine("Done...");
    Console.ReadLine();
}

Worked beautifully. When I am using ZackOfAllTrades' code, VS profiler shows memory consumption at about 2.5 times the size of file. Eg: if the file is 1.5GB large, the memory consumption is roughly 4GB. But if one is to copy to file system directly, the memory consumption is negligible (<50mb).

The other issue is with MediaDevice.FriendlyName. I know for sure my Xiaomi Note 10 Pro did not support FriendlyName. What worked for me is MediaDevice.Description.

Upvotes: 3

ZackOfAllTrades
ZackOfAllTrades

Reputation: 637

I used nugetpackage "Media Devices by Ralf Beckers v1.8.0" This made it easy for me to copy my photos from my device to my computer and vice versa.

 public class Program
{
    static void Main(string[] args)
    {
        var devices = MediaDevice.GetDevices();
        using (var device = devices.First(d => d.FriendlyName == "Galaxy Note8"))
        {
            device.Connect();
            var photoDir = device.GetDirectoryInfo(@"\Phone\DCIM\Camera");

            var files = photoDir.EnumerateFiles("*.*", SearchOption.AllDirectories);

            foreach (var file in files)
            {
                MemoryStream memoryStream = new System.IO.MemoryStream();
                device.DownloadFile(file.FullName, memoryStream);
                memoryStream.Position = 0;
                WriteSreamToDisk($@"D:\PHOTOS\{file.Name}", memoryStream);
            }
            device.Disconnect();
        }

    }

    static void WriteSreamToDisk(string filePath, MemoryStream memoryStream)
    {
        using (FileStream file = new FileStream(filePath, FileMode.Create, System.IO.FileAccess.Write))
        {
            byte[] bytes = new byte[memoryStream.Length];
            memoryStream.Read(bytes, 0, (int)memoryStream.Length);
            file.Write(bytes, 0, bytes.Length);
            memoryStream.Close();
        }
    }
}

Upvotes: 9

Related Questions