Copying pictures with ADB
I’ve been copying pictures from my Android phone to my Mac using Android File Transfer. It worked great when my pictures were stored in the phone’s internal storage. However, now that I’m storing my pictures on an external SD card, it has become unreliable. More and more frequently, I’ve been getting:
despite having my screen unlocked. Unplugging and reconnecting the USB cable repeatedly sometimes works eventually, but lately it’s been getting less and less likely to work. I wish software would just work correctly, instead of being so buggy and crappy. But that’s a gripe for another post sometime.
Anyway, I decided to use the Android Debug Bridge (adb) command-line tool to copy my photos. I wrote the following Haskell program to determine which photos I don’t yet have on my computer, and then copy them. It works great!
#!/usr/bin/env runhaskell
import Data.List
import System.Directory
import System.IO
import System.Process
remoteDir = "/storage/extSdCard/DCIM/Camera"
localDir = "/Users/ppelleti/Pictures/Android"
getRemoteFiles :: String -> IO [String]
getRemoteFiles remoteDir = do
files <- readProcess "adb" ["shell", "ls", remoteDir] ""
return $ lines $ filter (/= '\r') files
getLocalFiles :: String -> IO [String]
getLocalFiles localDir = do
files <- getDirectoryContents localDir
return $ filter shouldKeep files
where shouldKeep ('.':_ ) = False
shouldKeep _ = True
copyOneFile :: String -> String -> IO ()
copyOneFile remoteFile localFile =
cmd ["adb", "pull", "-a", remoteFile, localFile]
cmd :: [String] -> IO ()
cmd (exe:args) = do
putStrLn $ unwords $ exe : map show args
callProcess exe args
copyFiles :: String -> String -> [String] -> IO ()
copyFiles rDir lDir files =
mapM_ cfile files
where cfile file = copyOneFile (rDir ++ "/" ++ file) (lDir ++ "/" ++ file)
copyNewFiles :: String -> String -> IO ()
copyNewFiles rDir lDir = do
rFiles <- getRemoteFiles rDir
lFiles <- getLocalFiles lDir
let files = rFiles \\ lFiles
copyFiles rDir lDir files
main = copyNewFiles remoteDir localDir
Also available as a gist.