How to get a list of all image files for a slide show - basic4android

This code works, in the sense that it crawls the directories. However it gets an exception on all the sub directories, and fails to return any files. Is this a permissions issue, or is there something wrong in my code?
ES file manager shows the files, there are at least 3 folders with images in them.
Sub AddImagesToMap(Dir As String) As Map'crawl tree for images
Dim fn As String , i As Int
Dim CRList As List, Ext As String
Try
CRlist.initialize
CRList=File.ListFiles(Dir)
For i = 0 To CRlist.Size-1'jpg,png and gif
fn=CRList.Get(i)
Select fn 'ignore some system folders
Case "/dev"
Case "/proc"
Case "/sys"
Case "/system"
Case Else
If File.IsDirectory(Dir,CRList.Get(i)) Then
Log("Dir:"&fn)
AddImagesToMap(fn)
Else
Log(fn)
Ext= common.FileExt(fn)
If ext.ToLowerCase="jpg" OR ext.ToLowerCase="png" OR ext.ToLowerCase="gif" Then
Imagelist.Put(fn, Dir)
End If
End If
End Select
Next
Catch
Log ("error:"&Dir)
End Try
End Sub

I believe this will fix your problem: when looking to see if a directory has any files in it, it may be empty. I too used the File.ListFiles function. When a folder is empty it returns an uninitialized result, which if you try to use an uninitialized variable will cause an exception. Here's what I did:
f1 = File.ListFiles(x)
If f1.IsInitialized=False Then
f1.Initialize
End If
By the way, when I was trying to understand the File.ListFiles functions this code you posted on B4A was the only example I could find. So thanks, and I hope this solves your problem.

I use this to get my mp3 amd m4a music files from my music folder.
Sub Activity_Create(FirstTime As Boolean)
ListView1.Initialize("ListView1")
Dim GD As GradientDrawable
GD.Initialize("TR_BL", Array As Int(Colors.Gray, Colors.LightGray))
Activity.Background = GD
ListView1.ScrollingBackgroundColor = Colors.Transparent
Dim Bitmap1 As Bitmap
Bitmap1.Initialize(File.DirAssets, "button.gif")
ListView1.SingleLineLayout.ItemHeight = 50dip
ListView1.SingleLineLayout.Label.TextSize = 20
ListView1.SingleLineLayout.Label.TextColor = Colors.Blue
ListView1.SingleLineLayout.Label.Gravity = Gravity.LEFT
ListView1.FastScrollEnabled = True
root=File.DirRootExternal
filePath = root & "/music/"
FindFolder(filePath,"")
Activity.AddView(ListView1, 0, 0, 100%x, 100%y)
End Sub
Sub FindFolder(myPath As String, subfolder As String) As String
Dim fileList As List
Dim i As Int
Dim p,f As String
fileList = File.ListFiles(myPath)
fileList.Sort(True)
For i = 0 To fileList.Size-1
p = myPath
f = fileList.Get(i)
If File.IsDirectory(p, f) Then
p = p & "/" & f
p = FindFolder(p, subfolder) '<---recursive
Else
If f.EndsWith("m4a") OR f.EndsWith("mp3") Then
album = p.SubString(p.LastIndexOf("/")+1) 'treat folders names as artist or album
song = f.SubString2(0,f.LastIndexOf(".")) 'treat files as musc remoce extension name
ListView1.AddSingleLine(album & " : " & song)
End If
End If
Next
End Sub

I know that's a bit late, but I figured it out.
Here's how I can get all files:
Sub AddImagesToMap(Dir As String) 'crawl tree for files
Dim fn As String , i As Int
Dim CRList As List
Try
CRList.initialize
CRList=File.ListFiles(Dir)
For i = 0 To CRList.Size-1'jpg,png and gif
fn=CRList.Get(i)
If File.IsDirectory(Dir,CRList.Get(i)) Then
Log("Dir: "&fn)
AddImagesToMap(Dir & "/" & fn)
Else
Log(fn & " - " & Dir)
End If
Next
Catch
Log ("Error: "&Dir)
End Try
End Sub
Hope I helped a lot of people with the same question.
EDIT: Here's a better version of mine. Here I sort the file types:
Sub AddImagesToMap(Dir As String)
Dim fn As String , i As Int
Dim CRList As List, Ext As String
Try
CRList.initialize
CRList=File.ListFiles(Dir)
For i = 0 To CRList.Size-1
fn=CRList.Get(i)
If File.IsDirectory(Dir,CRList.Get(i)) Then
AddImagesToMap(Dir & "/" & fn)
Else
If fn.Contains(".") Then
Ext=fn.SubString(fn.LastIndexOf("."))
End If
Select Case Ext
Case ".jpg"
Log(fn & " - " & Dir)
Case ".png"
Log(fn & " - " & Dir)
End Select
End If
Next
Catch
Log ("Error: "&Dir)
End Try
End Sub

Related

How to handle .doc corruption and password protected .doc files in python

I have a folder with 20,000 .doc/docx files in it. I needed to convert all of these to .pdf. I decided to go to python to achieve this and was able to put together a quick and dirty code to achieve the output. However I had to babysit the process as I would occasionally come across a corrupt .doc or .docx file or a password protected file. In these instances I would just like to skip over these files and continue on. I ended up having to find the file in question and remove from the folder and continue on. I have dug around in the win32com documentation but was unable to find anything. Code below
from os import chdir, getcwd, listdir, path
from time import strftime
from win32com import client
def count_files(filetype):
''' (str) -> int
Returns the number of files given a specified file type.
>>> count_files(".docx")
11
'''
count_files = 0
for files in listdir(folder):
if files.endswith(filetype):
count_files += 1
return count_files
# Function "check_path" is used to check whether the path the user provided does
# actually exist. The user is prompted for a path until the existence of the
# provided path has been verified.
def check_path(prompt):
''' (str) -> str
Verifies if the provided absolute path does exist.
'''
abs_path = raw_input(prompt)
while path.exists(abs_path) != True:
print ("\nThe specified path does not exist.")
abs_path = raw_input(prompt)
return abs_path
print ("\n")
folder = "My Absolute Folder Path Here"
# Change the directory.
chdir(folder)
# Count the number of docx and doc files in the specified folder.
num_docx = count_files(".docx")
num_doc = count_files(".doc")
# Check if the number of docx or doc files is equal to 0 (= there are no files
# to convert) and if so stop executing the script.
if num_docx + num_doc == 0:
print ("\nThe specified folder does not contain docx or docs files.")
print (strftime("%H:%M:%S"), "There are no files to convert. BYE, BYE!.")
exit()
else:
print ("\nNumber of doc and docx files: ", num_docx + num_doc, "")
print (strftime("%H:%M:%S"), "Starting to convert files ...")
# Try to open win32com instance. If unsuccessful return an error message.
try:
word = client.DispatchEx("Word.Application")
for files in listdir(getcwd()):
if files.endswith(".docx"):
new_name = files.replace(".docx", r".pdf")
in_file = path.abspath(folder + "\\" + files)
new_file = path.abspath(folder + "\\" + new_name)
doc = word.Documents.Open(in_file)
print (strftime("%H:%M:%S"), " docx -> pdf ", path.relpath(new_file))
doc.SaveAs(new_file, FileFormat = 17)
doc.Close()
if files.endswith(".doc"):
new_name = files.replace(".doc", r".pdf")
in_file = path.abspath(folder + "\\" + files)
new_file = path.abspath(folder + "\\" + new_name)
doc = word.Documents.Open(in_file)
print (strftime("%H:%M:%S"), " doc -> pdf ", path.relpath(new_file))
doc.SaveAs(new_file, FileFormat = 17)
doc.Close()
except Exception as e:
print (e)
finally:
word.Quit()
print ("\n", strftime("%H:%M:%S"), "Finished converting files.")
# Count the number of pdf files.
num_pdf = count_files(".pdf")
print ("\nNumber of pdf files: ", num_pdf)
# Check if the number of docx and doc file is equal to the number of files.
if num_docx + num_doc == num_pdf:
print ("\nNumber of doc and docx files is equal to number of pdf files.")
else:
print ("\nNumber of doc and docx files is not equal to number of pdf files.")
The following code is what I use (Excel VBA) to create PDF. It's the best I can do to help you. Hope it helps.
Sub WordtoPDF()
'OPEN IN EXCEL
'takes files from a location of particular file type, uses WORD to save them as PDFs to new location
Dim strOldFileName As String
Dim strOldPath As String
Dim strNewFileName As String
Dim strNewPath As String
Dim OldType As String
Dim NewType As String
Dim AraryFileNames() As String
Dim Path as String
Dim coll As Collection
Set coll = New Collection
'Allows to be used on any folder
Do While strOldPath = "" Or strOldPath = "False"
strOldPath = Application.InputBox("FolderPath containing Original files", "FolderPath eg C:\temp", "C:\temp", Type:=2)
If Dir(strOldPath, vbDirectory) = "" Then
MsgBox ("Directory doesn't exist")
Exit Sub
Else
End If
Loop
Do While OldType = "" Or OldType = "False" Or InStr(OldType, ".") <> 0
OldType = Application.InputBox("Original file's filetype", "FolderPath eg docx", "docx", Type:=2)
Loop
Do While strNewPath = "" Or strOldPath = "False"
strNewPath = Application.InputBox("location of NEW files.", "FolderPath eg C:\temp", strOldPath, Type:=2)
If Dir(strNewPath, vbDirectory) = "" Then
MsgBox ("Directory doesn't exist")
Exit Sub
Else
End If
Loop
Do While NewType = "" Or NewType = "False" Or InStr(NewType, ".") <> 0
NewType = Application.InputBox("file type to convert files to", "FolderPath eg docx becomes pdf", "pdf", Type:=2)
Loop
'AAAAA
'Counts how many files there are in the folder with the ".docx"(OldType) ending and makes a collection of their names
'creates a collection of with only "OldType" filetype.
Path = strOldPath & "\*." & OldType
fileName = Dir(Path)
coll.Add fileName
Do While fileName <> ""
Count = Count + 1
fileName = Dir()
coll.Add fileName
Loop
Dim item As Variant
On Error GoTo line1:
For Each item In coll
For i = 1 To coll.Count
If UCase(Right(coll(i), Len(OldType))) <> UCase(OldType) Then
coll.Remove (i)
i = 0
Else
End If
Next i
Next item
line1:
On Error GoTo 0
'AAAAA
'BBBBB
'Checks new location to make sure that files won't be saving over existing files
'collection file names with NewType extension checks to see if unique in new location.
On Error GoTo Error:
For i = 1 To coll.Count
Path2 = strNewPath & "\*." & NewType
fileName2 = Dir(Path2)
Do While fileName2 <> ""
If UCase(Left(coll(i), Len(coll(i)) - Len(OldType)) & NewType) = UCase(fileName2) Then
MsgBox (Left(coll(i), Len(coll(i)) - Len(OldType)) & NewType & " already exists in " & strNewPath)
Exit Sub
Else
End If
fileName2 = Dir()
Loop
Next i
Error:
On Error GoTo 0
'BBBBB
'CCCCC
'Opens each Old Type file in the original location using word, and saves as PDF with the same name in the new location
Set appWD = CreateObject("Word.Application")
For i = 1 To coll.Count
TempString = strOldPath & "\" & Left(coll(i), Len(coll(i)) - Len(OldType) - 1) & "." & OldType
Set objDoc = appWD.Documents.Open(fileName:=TempString)
TempString2 = strNewPath & "\" & Left(coll(i), Len(coll(i)) - Len(OldType) - 1) & "." & NewType
objDoc.ExportAsFixedFormat OutputFileName:=TempString2, ExportFormat:=17 '17 = wdExportFormatPDF
Next i
'CCCCC
If Not appWD Is Nothing Then
appWD.Quit
Set appWD = Nothing
End If
End Sub

Getting user id from facebook

I wonder is it still possible to get Facebook user ID if I got 'only' the user's profile (profile username/link)?
For instance:
https://www.facebook.com/zuck
I've tried to do this with SDK and Graph API but it seems that all previous solutions don't work. Could you please give me a hint? I would like to go further but I'm not sure which way is correct.
You can do it with Excel. I put the macros that I use. You have to put the name in the first column and it will generate the id in the second column when you run the GenerateFaceIds macro. (You need to be logged into Facebook in IExplorer)
Sub GenerateFaceIds()
Dim total As Long
total = 1
Do Until IsEmpty(Cells(total, 1)) = True
If (Cells(total, 2) = "") Then
Call faceId(total)
End If
total = total + 1
Loop
MsgBox ("OK")
End Sub
Sub faceId(row As Long)
On Error GoTo ErrHandler
Dim appIE As Object
Set appIE = CreateObject("internetexplorer.application")
Dim id As String
id = Cells(row, 1)
With appIE
.Navigate "https://www.facebook.com/" + id
.Visible = False
End With
Do While appIE.Busy
DoEvents
Loop
Text = appIE.Document.Body.innerHTML
posinter = InStr(Text, "profile_owner")
profile_owner = Mid(Text, posinter + 16, 15)
posinter2 = InStr(profile_owner, """")
If posinter2 > 0 Then
profile_owner = Left(profile_owner, posinter2 - 1)
End If
Cells(row, 2) = profile_owner
appIE.Quit
Set appIE = Nothing
ExitSub:
Exit Sub
ErrHandler:
'MsgBox "Something's wrong"
appIE.Quit
Set appIE = Nothing
Resume ExitSub
Resume
End Sub
Result:
zuck 4

simplest Unostructure that supports he getByName

In LibreOffice Basic sub I use a bunch of uno properties in an array. Which is the simplest Unostructure or UnoService that I must "embed" them, in order to use the getByName "function"?
Example:
dim props(1) as new com.sun.star.beans.PropertyValue
props(0).Name = "blahblah1"
props(0).Value = "blahblah1Value"
props(1).Name = "blahblah2"
props(1).Name = 3000
I want to be able to use something like:
b = props.getByName("blahblah2").Value
or something like (assuming I "assigned" them in a structure-like-object called "somestruct") :
b = somestruct.getprops.getByName("blahblah2").Value
As I understand that this can be done by creating a "UnoService" which supports the getByName and then, somehow, assigning these props to this service
Which is the "lightest" such service?
(I mean the service that uses less resources)
Thanks in advance.
Really supporting the interface XNameAccess is not as easy. The services which implement this interface are supposed using this interface for existing named properties, not for own created ones.
But you can use the service EnumerableMap to achieve what you probably want.
Example:
sub testEnumerableMap
serviceEnumerableMap = com.sun.star.container.EnumerableMap
oEnumerableMap = serviceEnumerableMap.create("string", "any")
oEnumerableMap.put("blahblah1", "blahblah1Value")
oEnumerableMap.put("blahblah2", 3000)
oEnumerableMap.put("blahblah3", 1234.67)
msgbox oEnumerableMap.get("blahblah1")
msgbox oEnumerableMap.get("blahblah2")
msgbox oEnumerableMap.get("blahblah3")
'msgbox oEnumerableMap.get("blahblah4") 'will throw error
msgbox oEnumerableMap.containsKey("blahblah2")
msgbox oEnumerableMap.containsValue(3000)
if oEnumerableMap.containsKey("blahblah4") then
msgbox oEnumerableMap.get("blahblah4")
end if
end sub
But starbasic with option Compatible is also able supporting Class programming like VBA does.
Example:
Create a module named myPropertySet. Therein put the following code:
option Compatible
option ClassModule
private aPropertyValues() as com.sun.star.beans.PropertyValue
public sub setProperty(oProp as com.sun.star.beans.PropertyValue)
bUpdated = false
for each oPropPresent in aPropertyValues
if oPropPresent.Name = oProp.Name then
oPropPresent.Value = oProp.Value
bUpdated = true
exit for
end if
next
if not bUpdated then
iIndex = ubound(aPropertyValues) + 1
redim preserve aPropertyValues(iIndex)
aPropertyValues(iIndex) = oProp
end if
end sub
public function getPropertyValue(sName as string) as variant
getPropertyValue = "N/A"
for each oProp in aPropertyValues
if oProp.Name = sName then
getPropertyValue = oProp.Value
exit for
end if
next
end function
Then within a standard module:
sub testClass
oPropertySet = new myPropertySet
dim prop as new com.sun.star.beans.PropertyValue
prop.Name = "blahblah1"
prop.Value = "blahblah1Value"
oPropertySet.setProperty(prop)
prop.Name = "blahblah2"
prop.Value = 3000
oPropertySet.setProperty(prop)
prop.Name = "blahblah3"
prop.Value = 1234.56
oPropertySet.setProperty(prop)
prop.Name = "blahblah2"
prop.Value = 8888
oPropertySet.setProperty(prop)
msgbox oPropertySet.getPropertyValue("blahblah1")
msgbox oPropertySet.getPropertyValue("blahblah2")
msgbox oPropertySet.getPropertyValue("blahblah3")
msgbox oPropertySet.getPropertyValue("blahblah4")
end sub
LibreOffice Basic supports the vb6 Collection type.
Dim coll As New Collection
coll.Add("blahblah1Value", "blahblah1")
coll.Add(3000, "blahblah2")
MsgBox(coll("blahblah1"))
Arrays of property values are the only thing that will work for certain UNO interfaces such as dispatcher calls. If you simply need a better way to deal with arrays of property values, then use a helper function.
Sub DisplayMyPropertyValue
Dim props(0 To 1) As New com.sun.star.beans.PropertyValue
props(0).Name = "blahblah1"
props(0).Value = "blahblah1Value"
props(1).Name = "blahblah2"
props(1).Name = 3000
MsgBox(GetPropertyByName(props, "blahblah1"))
End Sub
Function GetPropertyByName(props As Array, propname As String)
For Each prop In props
If prop.Name = propname Then
GetPropertyByName = prop.Value
Exit Function
End If
Next
GetPropertyByName = ""
End Function
XNameAccess is used for UNO containers such as Calc sheets. Normally these containers are obtained from the UNO interface, not created.
oSheet = ThisComponent.Sheets.getByName("Sheet1")
May UNO objects support the XPropertySet interface. Normally these are also obtained from the UNO interface, not created.
paraStyleName = cellcursor.getPropertyValue("ParaStyleName")
It may be possible to create a new class in Java that implements XPropertySet. However, Basic uses helper functions instead of class methods.
I think the serviceEnumerableMap is the answer (so far). Creating the values and searching them was much faster then creating props in a dynamic array and searching them with a for loop in basic.
(I do not "dare" to use "option Compatible", although I was a big fun of VB6 and VBA, because of the problems in code that maybe arise).
I used this code to test time in a form:
SUB testlala(Event)
TESTPROPS(Event)
' TESTENUM(Event)
MSGBOX "END OF TEST"
END SUB
SUB TESTENUM(Event)
DIM xcounter AS LONG
'b = now()
serviceEnumerableMap = com.sun.star.container.EnumerableMap
oEnumerableMap = serviceEnumerableMap.create("string", "any")
FOR xcounter= 0 TO 10000
oEnumerableMap.put("pr" & FORMAT(xcounter,"0000"), xcounter -10000)
NEXT
'b=now()-b
b = now()
FOR xcounter = 1 TO 5000
lala = Int((9000 * Rnd) +1)
g =oEnumerableMap.get("pr" & FORMAT(lala,"0000"))
'MSGBOX GetValueFromName(props,"pr" & FORMAT(xcounter,"0000"))
NEXT
b=now()-b
MSGBOX b*100000
END SUB
SUB TESTPROPS(Event)
DIM props()
DIM xcounter AS LONG
'b = now()
FOR xcounter= 0 TO 10000
AppendProperty(props,"pr" & FORMAT(xcounter,"0000"), xcounter -10000)
NEXT
'b=now()-b
b = now()
FOR xcounter = 1 TO 5000
lala = Int((9000 * Rnd) +1)
g = GetValueFromName(props,"pr" & FORMAT(lala,"0000"))
'MSGBOX GetValueFromName(props,"pr" & FORMAT(xcounter,"0000"))
NEXT
b=now()-b
MSGBOX b*100000
END SUB
REM FROM Andrew Pitonyak's OpenOffice Macro Information ------------------
Sub AppendToArray(oData(), ByVal x)
Dim iUB As Integer 'The upper bound of the array.
Dim iLB As Integer 'The lower bound of the array.
iUB = UBound(oData()) + 1
iLB = LBound(oData())
ReDim Preserve oData(iLB To iUB)
oData(iUB) = x
End Sub
Function CreateProperty(sName$, oValue) As com.sun.star.beans.PropertyValue
Dim oProperty As New com.sun.star.beans.PropertyValue
oProperty.Name = sName
oProperty.Value = oValue
CreateProperty() = oProperty
End Function
Sub AppendProperty(oProperties(), sName As String, ByVal oValue)
AppendToArray(oProperties(), CreateProperty(sName, oValue))
End Sub

Can images be read from an iPhone programmatically using CreateFile in Windows?

When an iPhone is connected to a Win7 computer, the images can be viewed using Explorer (and the open file dialog of my app). However, the file location does not contain a drive letter.
For example Computer\Apple iPhone\Internal Storage\DCIM\800AAAAA\IMG_0008.JPG instead of E:\DCIM\800AAAAA\IMG_0008.JPG which is common of sdcards, usb drives, etc...
I've tried using CreateFileW to read images from an iPhone but it fails with '(Error Code: 3) The system cannot find the path specified.' I've also tried accessing them with Chrome and it fails too.
Any suggestions?
The folder is actually what is referred to as a 'Virtual Folder' and does not have a full path on the file system. You will need to use the shell item returned from the open dialog to get the content of the file rather than using CreateFile.
The data should be accessible, but you should follow the instructions from the MSDN documentation. I'm sure there are probably better examples (as this only gives guidelines).
edit the rough process is to get the IShellItem from IFileOpenDialog, then to bind to the stream and then read the stream (assuming reading only) - bear in mind that this code is pretty much without error handling or checking or safety:
if (pitem->GetDisplayName(SIGDN_NORMALDISPLAY, &destName) == S_OK) {
std::cout << destName << std::endl;
CoTaskMemFree(destName);
}
IStream *pistream;
if (pitem->BindToHandler(0, BHID_Stream, IID_PPV_ARGS(&pistream)) == S_OK) {
char input[1024];
long to_read = 1024;
unsigned long read;
while (S_OK == pistream->Read(input, to_read, &read)) {
std::cout << input << std::endl;
}
pistream->Release();
}
pitem->Release();
Most often such a device is inserted in the Windows Explorer as a Shell Namespace Extension and not like an USB stick with drive letter. Most of the normal file commands like CopyFile(..), FindFirst() or GetFileInfo(..) can not be used directly in such a Shell Namespace extension. Only the CopyHere(..) is working.
I needed long time to figure out how to enumerate the files on a digicam and now also on an Android device with an vb.net program and to copy my pictures to my Windows PC:
Public Const MyComputer As Integer = &H11&
Sub EnumMyComputer()
Dim oItem As Object
Dim res As Integer
For Each oItem In DirectCast(CreateObject("Shell.Application").Namespace(MyComputer).Items, System.Collections.IEnumerable)
Debug.Print(oItem.Type.ToString)
if oItem.Type.ToString="Tragbares Medienwiedergabegerät" then '<- check, adopt!
res = EnumNamespaceItems(oItem, "", oItem.Name.ToString, 0)
End If
Next oItem
End Sub
Function EnumNamespaceItems(oItem As Object, SrcCPath As String, SrcDPath As String, folderLevel As Integer) As Integer
Dim y As Object
Dim tempFullFileName As String
Debug.Print(StrDup(folderLevel, " ") & "\" & oItem.Name.ToString & " (" & oItem.Path.ToString & ")")
For Each y In DirectCast(oItem.GetFolder.items, System.Collections.IEnumerable)
'Debug.Print(StrDup(folderLevel, " ") & SrcDPath & y.Name.ToString)
If y.IsFolder = True Then
Dim n1 As Integer
n1 = EnumNamespaceItems(y, SrcCPath & y.Path.ToString & "\", SrcDPath & y.Name.ToString & "\", 1 + folderLevel)
If n1 < 0 Then 'failure: Cancel
EnumNamespaceItems = n1
Exit Function
End If
Else 'it's a file:
Debug.Print(StrDup(folderLevel, " ") & " " & y.Name.ToString)
tempFullFileName = System.IO.Path.GetTempPath() & y.Name.ToString
' CopyFile is not possible here if SrcCPath is like "::{…}…":
' My.Computer.FileSystem.CopyFile(SrcCPath & y.Name.ToString , fFile.FullName)
Dim suc As Integer = CopyHereFileWait(y, My.Computer.FileSystem.SpecialDirectories.Temp)
If suc >= 0 Then 'now we can do things like this:
Dim MyFileInfo As System.IO.FileInfo = My.Computer.FileSystem.GetFileInfo(tempFullFileName)
Dim fileDate As Date = MyFileInfo.LastWriteTime
End If 'suc
End If 'else y.IsFolder
Next y
EnumNamespaceItems = 0
End Function
Function CopyHereFileWait(sourceNamespaceObject As Object, targetFolder As String) As Integer
Dim fsMyStream As System.IO.FileStream
Dim n1 As Integer
Dim taregetFullFileName As String
n1 = Len(targetFolder)
If Mid(targetFolder, n1, 1) = "\" Then
targetFolder = Microsoft.VisualBasic.Left(targetFolder, n1 - 1)
End If
taregetFullFileName = targetFolder & "\" & sourceNamespaceObject.Name.ToString
Dim oNsTargetFolder As Object
oNsTargetFolder = CreateObject("Shell.Application").Namespace(CStr(targetFolder))
oNsTargetFolder.copyHere(sourceNamespaceObject)
'returns immediately and is doing the work in the background
n1 = 0
Do
Threading.Thread.Sleep(50) 'ms
Try
fsMyStream = System.IO.File.Open(taregetFullFileName, IO.FileMode.Open, IO.FileAccess.ReadWrite)
fsMyStream.Close()
CopyHereFileWait = n1
Exit Function
Catch ex As Exception
Debug.Print(ex.Message)
End Try
n1 = n1 + 1
Loop While n1 < 400 'timeout 400*50ms = 20s
CopyHereFileWait = -n1
End Function
You may add to check for folders with y.Name.ToString="DCIM" (on folderLevel=1) and for files with ".jpg".

Renaming a Word document and saving its filename with its first 10 letters

I have recovered some Word documents from a corrupted hard drive using a piece of software called photorec. The problem is that the documents' names can't be recovered; they are all renamed by a sequence of numbers. There are over 2000 documents to sort through and I was wondering if I could rename them using some automated process.
Is there a script I could use to find the first 10 letters in the document and rename it with that? It would have to be able to cope with multiple documents having the same first 10 letters and so not write over documents with the same name. Also, it would have to avoid renaming the document with illegal characters (such as '?', '*', '/', etc.)
I only have a little bit of experience with Python, C, and even less with bash programming in Linux, so bear with me if I don't know exactly what I'm doing if I have to write a new script.
How about VBScript? Here is a sketch:
FolderName = "C:\Docs\"
Set fs = CreateObject("Scripting.FileSystemObject")
Set fldr = fs.GetFolder(Foldername)
Set ws = CreateObject("Word.Application")
For Each f In fldr.Files
If Left(f.name,2)<>"~$" Then
If InStr(f.Type, "Microsoft Word") Then
MsgBox f.Name
Set doc = ws.Documents.Open(Foldername & f.Name)
s = vbNullString
i = 1
Do While Trim(s) = vbNullString And i <= doc.Paragraphs.Count
s = doc.Paragraphs(i)
s = CleanString(Left(s, 10))
i = i + 1
Loop
doc.Close False
If s = "" Then s = "NoParas"
s1 = s
i = 1
Do While fs.FileExists(s1)
s1 = s & i
i = i + 1
Loop
MsgBox "Name " & Foldername & f.Name & " As " & Foldername & s1 _
& Right(f.Name, InStrRev(f.Name, "."))
'' This uses copy, because it seems safer
f.Copy Foldername & s1 & Right(f.Name, InStrRev(f.Name, ".")), False
'' MoveFile will copy the file:
'' fs.MoveFile Foldername & f.Name, Foldername & s1 _
'' & Right(f.Name, InStrRev(f.Name, "."))
End If
End If
Next
msgbox "Done"
ws.Quit
Set ws = Nothing
Set fs = Nothing
Function CleanString(StringToClean)
''http://msdn.microsoft.com/en-us/library/ms974570.aspx
Dim objRegEx
Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.IgnoreCase = True
objRegEx.Global = True
''Find anything not a-z, 0-9
objRegEx.Pattern = "[^a-z0-9]"
CleanString = objRegEx.Replace(StringToClean, "")
End Function
Word documents are stored in a custom format which places a load of binary cruft on the beginning of the file.
The simplest thing would be to knock something up in Python that searched for the first line beginning with ASCII chars. Here you go:
#!/usr/bin/python
import glob
import os
for file in glob.glob("*.doc"):
f = open(file, "rb")
new_name = ""
chars = 0
char = f.read(1)
while char != "":
if 0 < ord(char) < 128:
if ord("a") <= ord(char) <= ord("z") or ord("A") <= ord(char) <= ord("Z") or ord("0") <= ord(char) <= ord("9"):
new_name += char
else:
new_name += "_"
chars += 1
if chars == 100:
new_name = new_name[:20] + ".doc"
print "renaming " + file + " to " + new_name
f.close()
break;
else:
new_name = ""
chars = 0
char = f.read(1)
if new_name != "":
os.rename(file, new_name)
NOTE: if you want to glob multiple directories you'll need to change the glob line accordingly. Also this takes no account of whether the file you're trying to rename to already exists, so if you have multiple docs with the same first few chars then you'll need to handle that.
I found the first chunk of 100 ASCII chars in a row (if you look for less than that you end up picking up doc keywords and such) and then used the first 20 of these to make the new name, replacing anything that's not a-z A-Z or 0-9 with underscores to avoid file name issues.