I am using a function to select a few files:
Module OpenFileMod
Public Function OpenFile() As String()
'declare a string, this is will contain the filename that we return
Dim strFileNames As String()
'declare a new open file dialog
Dim fileDialogBox As New OpenFileDialog()
fileDialogBox.Filter = "Excel Files (*.xls)|*.xls"
fileDialogBox.Multiselect = True
'this line tells the file dialog box what folder it should start off in first
'I selected the users my document folder
fileDialogBox.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
'Check to see if the user clicked the open button
If (fileDialogBox.ShowDialog() = DialogResult.OK) Then
strFileNames = fileDialogBox.FileNames
Else
MsgBox("You did not select a file!")
End If
'return the name of the file
Return strFileNames
End Function
End Module
I would like to know how many files the user has chosen.
How can I do that?
fileDialogBox.FileNames is an array, so you can simply check its Length property
or
strFileNames.Length
Related
I'm very new to coding so any help is appreciated.
I've created a simple listbox that displays an array from a text file.
I wanted to add a textbox and a delete button so the user can type a word and then delete that line from the text file.
I've read many forums with various solutions for this but all have returned errors - currently I am getting this error: "System.IO.IOException: 'The process cannot access the file 'C:\Users\hches\source\repos\Inventory\Inventory\bin\Debug\Stock.txt' because it is being used by another process.'"
in sub DeleteLine()
Here is the relevant code to the Delete button and the respective DeleteLine() sub:
Private Sub BTDel_Click(sender As Object, e As EventArgs) Handles BTDel.Click
Dim sr As New StreamReader("Stock.txt")
Dim i As Integer = 0
Dim deleted As Boolean = False
If TBSearch.Text = "" Then
MsgBox("Please enter an Item to Delete.")
Else
Do Until sr.Peek() = -1 Or deleted = True 'prevents it from looping through the whole stock if the item is deleted
Dim Itm As String = sr.ReadLine()
If Itm.Contains(TBSearch.Text) Or Itm.ToLower.Contains(TBSearch.Text.ToLower) Then 'if the line read from the text contains the search word, continue
MsgBox(TBSearch.Text & " has been deleted.") 'simple messagebox says it has been deleted
DeleteLine()
deleted = True
TBSearch.Clear()
ElseIf sr.Peek() = -1 Then 'if it reaches the end of the document and it hasn't been found
MsgBox("Item has not been deleted.") 'message box appears saying it is not deleted
deleted = False
TBSearch.Clear()
End If
i = i + 1
Loop
End If
End Sub
Public Sub DeleteLine()
Dim line As Integer = 0
Dim Filename = "Stock.txt"
Dim TheFileLines As New List(Of String)
For line = 0 To TheFileLines.Count
TheFileLines.AddRange(System.IO.File.ReadAllLines(Filename))
' if line is beyond end of list then exit sub
If line >= TheFileLines.Count Then Exit Sub
TheFileLines.RemoveAt(line)
System.IO.File.WriteAllLines(Filename, TheFileLines.ToArray)
Next
End Sub
Many thanks for any guidance,
Henry
SOLVED -- For anyone interested I will post my solution, thanks for the help.
Public Sub DeleteLine()
ArrayLoad() 'populates my array from text file
File.Delete("Stock.txt") 'deletes original text file
Dim stockList As List(Of String) = ItemNames.ToList 'creates a list using my array
stockList.Remove(TBSearch.Text) 'removes the searched item from the list
File.Create("Stock.txt").Dispose() 'creates a new text file (same name as the original so the program will work fine)
Using sw As New StreamWriter("Stock.txt") 'sets up a streamwriter to write the new list to the text file
For Each item As String In stockList
sw.WriteLine(item)
Next
sw.Flush()
sw.Close()
End Using
End Sub
End Class
I'd like to be able to delete individual files that are stored as attachments in an Access Database through VB.Net
I've managed to get storing, opening and "downloading" from an Access Database to work effectively, but the last piece of the puzzle would be to allow my end-user to delete an individual file in the attachments field.
This seems to be much harder than the other options as I can only seem to find information on how to delete the entire database entry, not just a single attachment. It gets even more complicated if there are more than one attachments stored against the entry.
I am using the following code to check what happens when the datagrid is clicked:
If e.ColumnIndex = ViewFileColum.Index Then
'Get the file name and contents for the selected attachment.
Dim gridRow = childgrid.Rows(e.RowIndex)
Dim tableRow = DirectCast(gridRow.DataBoundItem, DataRowView)
Dim fileName = CStr(tableRow(FILE_NAME_COLUMN_NAME))
Dim fileContents = GetFileContents(DirectCast(tableRow(FILE_DATA_COLUMN_NAME), Byte()))
DisplayTempFile(fileName, fileContents)
End If
If e.ColumnIndex = DownloadFileColumn.Index Then
'Get the file name and contents for the selected attachment.
MoveFile = True
Dim gridRow = childgrid.Rows(e.RowIndex)
Dim tableRow = DirectCast(gridRow.DataBoundItem, DataRowView)
Dim fileName = CStr(tableRow(FILE_NAME_COLUMN_NAME))
Dim fileContents = GetFileContents(DirectCast(tableRow(FILE_DATA_COLUMN_NAME), Byte()))
DisplayTempFile(fileName, fileContents)
End If
I want to add a third section that states if the DeleteFileColumn button is clicked then to remove that particular attachment from the database, but this doesn't seem possible.
When retrieving the information for the above two options, I use the following code:
Dim tempFolderPath = Path.GetTempPath()
Dim tempFilePath = Path.Combine(tempFolderPath, fileName)
'If the specified file exists, add a number to the name to differentiate them.
If File.Exists(tempFilePath) Then
Dim fileNumber = 1
Do
tempFilePath = Path.Combine(tempFolderPath,
String.Format("{0} ({1}){2}",
Path.GetFileNameWithoutExtension(fileName),
fileNumber,
Path.GetExtension(fileName)))
fileNumber += 1
Loop Until Not File.Exists(tempFilePath)
End If
'Save the file and open it.
'If "DOWNLOAD" button is clicked
If MoveFile = True Then
File.WriteAllBytes(SaveLocation & "\" & Path.GetFileNameWithoutExtension(fileName) & Path.GetExtension(fileName), fileContents)
MoveFile = False
'If "OPEN" button is clicked
Else
File.WriteAllBytes(tempFilePath, fileContents)
Dim attachmentProcess = Process.Start(tempFilePath)
If attachmentProcess Is Nothing Then
'Remember the file and try to delete it when this app closes.
tempFilePaths.Add(tempFilePath)
Else
'Remember the file and try to delete it when the associated process exits.
attachmentProcess.EnableRaisingEvents = True
AddHandler attachmentProcess.Exited, AddressOf attachmentProcess_Exited
tempFilePathsByProcess.Add(attachmentProcess, tempFilePath)
End If
End If
This code copies the information before opening it, so I don't ever actually deal with the file in the database directly. I've used adapted this code from another example I found online, but am having a hard time working out how to physically deal with the file on the database, or if its even possible?
Thanks
You need to create an Access DAO Recordset2 object for the attachments field, find the record corresponding to the specific attachment you want to delete, and then Delete() that record.
The following example will remove a document named "testDocument.pdf" from the attachments field for the record where ID=1:
' required COM reference:
' Microsoft Office 14.0 Access Database Engine Object Library
'
' Imports Microsoft.Office.Interop.Access.Dao
'
Dim dbe As New DBEngine
Dim db As Database = dbe.OpenDatabase("C:\Users\Public\Database1.accdb")
Dim rstMain As Recordset = db.OpenRecordset(
"SELECT Attachments FROM AttachTest WHERE ID=1",
RecordsetTypeEnum.dbOpenDynaset)
rstMain.Edit()
Dim rstAttach As Recordset2 = CType(rstMain.Fields("Attachments").Value, Recordset2)
Do Until rstAttach.EOF
If rstAttach.Fields("FileName").Value.Equals("testDocument.pdf") Then
rstAttach.Delete()
Exit Do
End If
rstAttach.MoveNext()
Loop
rstAttach.Close()
rstMain.Update()
rstMain.Close()
db.Close()
In LibreOffice 4.2 I am trying to open the file picker and select multiple files (which I succeeded), and then to transfer the names (and path) of those files to a variable (or array, does not matter).
Although I can open the file picker and select multiple files, I can get the file name and path of only one file (the first one). And I couldn't find any way to get the others.
I am using the following code:
Sub TakeFile()
Dim FileNames(0 to 100) as String
FileNames() = fImportLocalFile()
Msgbox FileNames
End Sub
Function fImportLocalFile() 'as String
' FJCC: Can't define the function as returning a String because now it returns an array
'this function opens a system file open dialog box and allows the
' user to pick a file from thier computer to open into the
' document for processing
'stores the filedialog object
Dim oFileDialog as Object
'stores the returned result of the activation of the dialog box
Dim iAccept as Integer
'stores the returned file name/path from the file dialog box
Dim sPath as String
'stores the set default path for the dialog box
Dim InitPath as String
'stores the types of files allowed in the filedialog
Dim sFilterNames as String
'setup the filters for the types of files to allow in the dialog
sFilterNames = "*.csv; *.txt; *.odt; *.ods; *.xls; *.xlt; *.xlsx"
'create the dialog box as a Windows File Dialog
oFileDialog = CreateUnoService("com.sun.star.ui.dialogs.FilePicker")
'set the filters for the dialog
oFileDialog.AppendFilter("Supported files", sFilterNames)
'set the path as blank
InitPath = ""
'add the default path to the dialog
oFileDialog.setDisplayDirectory(InitPath)
'setup the dialog to allow multiple files to be selected
oFileDialog.setMultiSelectionMode(True)
'set iAccept as the execution of the dialog
iAccept = oFileDialog.Execute()
'execute and test if dialog works
If iAccept = 1 Then
'set sPath as the chosen file from the dialog
'sPath = oFileDialog.Files(0)
FileArray = oFileDialog.getFiles() 'added by FJCC
'set the function as sPath for returning to the previous sub
fImportLocalFile = FileArray 'modified by FJCC
'end current if statement
End If
End Function
Your error is you are assigning the array of selected files to the funtion name itself! Choose a different name.
This works with me on LO 5.0.0.5
SUB TakeFile()
' Dim FileNames(0 to 100) as String
' Dont limit yourself!
FileNames = fImportLocalFile()
path = FileNames(0)
FOR i = 1 TO Ubound(FileNames)
print path + FileNames(i)
Next
End Sub
and within the function:
path = FileArray(0)
FOR i = 1 TO Ubound(FileArray)
print path + FileArray(i)
Next
fImportLocalFile = FileArray
There is a Interface XFilePicker2 which "extends file picker interface to workaround some design problems." This Interface has a Method getSelectedFiles.
See https://www.openoffice.org/api/docs/common/ref/com/sun/star/ui/dialogs/XFilePicker2.html.
Use this Method instead of XFilePicker.getFiles.
The following should work:
Sub TakeFile()
Dim FileNames() as String
FileNames = fImportLocalFile()
Msgbox Join(FileNames, Chr(10))
End Sub
Function fImportLocalFile() as Variant
Dim oFileDialog as Object
Dim iAccept as Integer
Dim sPath as String
Dim InitPath as String
Dim sFilterNames as String
sFilterNames = "*.csv; *.txt; *.odt; *.ods; *.xls; *.xlt; *.xlsx"
oFileDialog = CreateUnoService("com.sun.star.ui.dialogs.FilePicker")
oFileDialog.AppendFilter("Supported files", sFilterNames)
InitPath = ""
oFileDialog.setDisplayDirectory(InitPath)
oFileDialog.setMultiSelectionMode(True)
iAccept = oFileDialog.Execute()
If iAccept = 1 Then
fImportLocalFile = oFileDialog.getSelectedFiles()
Else
fImportLocalFile = Array()
End If
End Function
I wrote the following procedure to import, copy and paste the information from 5 workbooks into their designated worksheets of my main workbook. It is extremely important that the imported files are copied and pasted on the correct sheet, otherwise, my whole project's calculations fail.
The procedure is written so that if the file to be imported is not found in the designated path an Open File Dialog opens and the user can browse for the file. Once the file is found, the procedure imports that file into the main workbook.
It all works fine, but I jus realized that if a file is missing and the user checks an file name in the directory, it will bring in that file and paste it on the workbook. This is a problem, and I do not know how to prevent or warn the user from importing the wrong file.
In other words my loop starts as For n As Long = 1 to 5 Step 1 If the file that is missing is n=3 or statusReport.xls and the Open File Dialog opens, the user can select any file on that directory or any other and pasted on the designated sheet. What I want is to warn the user that it has selected a file not equal to n=3 or statusReport.xls
Here is the functions for the 5 worksheets to be imported and the sheets to be pasted on:
Public Function DataSheets(Index As Long) As Excel.Worksheet
'This function indexes both the data employee and position
'export sheets from Payscale.
'#param DataSheets, are the sheets to index
Select Case Index
Case 1 : Return xlWSEmployee
Case 2 : Return xlWSPosition
Case 3 : Return xlWSStatusReport
Case 4 : Return xlWSByDepartment
Case 5 : Return xlWSByBand
End Select
Throw New ArgumentOutOfRangeException("Index")
End Function
Public Function GetImportFiles(Index As Long) As String
'This function houses the 5 files
'used to import data to the project
'#param GetImportFiles, are the files to be
'imported and pasted on the DataSheets
Select Case Index
Case 1 : Return "byEmployee.csv"
Case 2 : Return "byPosition.csv"
Case 3 : Return "statusReport.xls"
Case 4 : Return "byDepartment.csv"
Case 5 : Return "byband.csv"
End Select
Throw New ArgumentOutOfRangeException("Index")
End Function
This is the procedure to import, copy and paste the files. It is heavily commented for my own sanity and for those trying to figure out what is going on. I also noted below where I need to insert the check to make sure that the file selected equals n
'This procedure imports the Client Listing.xlsx sheet. The procedure checks if the file is
'in the same directory as the template. If the file is not there, a browser window appears to allow the user
'to browse for the missing file. A series of message boxes guide the user through the process and
'verifies that the user picked the right file. The user can cancel the import at any time.
'Worksheet and Workbook Variables
Dim xlDestSheet As Excel.Worksheet
Dim xlWBPath As String = Globals.ThisWorkbook.Application.ActiveWorkbook.Path
Dim strImportFile As String
Dim xlWBSource As Object = Nothing
Dim xlWBImport As Object = Nothing
'Loop through the 5 sheets and files
For n As Long = 1 To 5 Step 1
strImportFile = xlWBPath & "\" & GetImportFiles(n)
xlDestSheet = DataSheets(n)
'Convert the indexed sheet name to a string
'so that it can be passed through the xlWB.Worksheets paramater
Dim strDestSheetName As String = xlDestSheet.Name
'If the file is found, then import, copy and paste the
'data into the corresponding sheets
If Len(Dir(strImportFile)) > 0 Then
xlWBSource = Globals.ThisWorkbook.Application.ActiveWorkbook
xlWBImport = Globals.ThisWorkbook.Application.Workbooks.Open(strImportFile)
xlWBImport.Worksheets(1).Cells.Copy(xlWB.Worksheets(strDestSheetName).Range("A1"))
xlWBImport.Close()
Else
'If a sheet is missing, prompt the user if they
'want to browse for the file.
'Messagbox variables
Dim msbProceed As MsgBoxResult
Dim strVmbProceedResults As String = ("Procedure Canceled. Your project will now close")
Dim strPrompt As String = " source file does not exist." & vbNewLine & _
"Press OK to browse for the file or Cancel to quit"
'If the user does not want to browse, then close the workbook, no changes saved.
msbProceed = MsgBox("The " & strImportFile & strPrompt, MsgBoxStyle.OkCancel + MsgBoxStyle.Question, "Verify Source File")
If msbProceed = MsgBoxResult.Cancel Then
msbProceed = MsgBox(strVmbProceedResults, MsgBoxStyle.OkOnly + MsgBoxStyle.Critical)
xlWB.Close(SaveChanges:=False)
Exit Sub
Else
'If the user does want to browse, then open the File Dialog
'box for the user to browse for the file
'Open Fil Dialog box variable and settings
Dim ofdGetOpenFileName As New OpenFileDialog()
ofdGetOpenFileName.Title = "Open File " & strImportFile
ofdGetOpenFileName.InitialDirectory = xlWBPath
ofdGetOpenFileName.Filter = "Excel Files (*.xls;*.xlsx; *.xlsm; *.csv)| *.xls; *.csv; *.xlsx; *.xlsm"
ofdGetOpenFileName.FilterIndex = 2
ofdGetOpenFileName.RestoreDirectory = True
'If the user presses Cancel on the box, warn that no
'file has been selected and the workbook will close
If ofdGetOpenFileName.ShowDialog() = System.Windows.Forms.DialogResult.Cancel Then
'Message box variables
Dim msbContinue As MsgBoxResult
Dim strAlert As String = ("You have not selected a workbook." & vbNewLine & _
"The project will now close without saving changes")
'Once the user presses OK, close the file and do not save changes
msbContinue = MsgBox(strAlert, MsgBoxStyle.OkOnly + MsgBoxStyle.Critical, "No Workbook Seletected")
xlWB.Close(SaveChanges:=False)
Exit Sub
Else
'If the user does select the file, then import the file
'copy and paste on workbook.
'***Here is where I need to check that strImportFile =n, if it does not warn the user******
strImportFile = ofdGetOpenFileName.FileName
xlWBImport = Globals.ThisWorkbook.Application.Workbooks.Open(strImportFile)
xlWBImport.Worksheets(1).Cells.Copy(xlWB.Worksheets(strDestSheetName).Range("A1"))
xlWBImport.Close()
End If
Try
'Import the remainder of the files
xlWBSource = Globals.ThisWorkbook.Application.ActiveWorkbook
xlWBImport = Globals.ThisWorkbook.Application.Workbooks.Open(strImportFile)
xlWBImport.Worksheets(1).Cells.Copy(xlWB.Worksheets(strDestSheetName).Range("A1"))
xlWBImport.Close()
Catch ex As Exception
MsgBox(Err.Description, MsgBoxStyle.Critical, "Unexpected Error")
End Try
End If
End If
Next
End Sub
Any help will be appreciated and/or any recommendations to improve my code as well.
thank you.
This looks like a possible application for a GoTo - objected to by many but it does still have its uses!!
Compare the file name with an if statement and if incorrect notify the user and return them to the browse dialog.
Else
Retry:
'If the user does want to browse, then open the File Dialog
'box for the user to browse for the file
'Open Fil Dialog box variable and settings
Dim ofdGetOpenFileName As New OpenFileDialog()
ofdGetOpenFileName.Title = "Open File " & strImportFile
ofdGetOpenFileName.InitialDirectory = xlWBPath
ofdGetOpenFileName.Filter = "Excel Files (*.xls;*.xlsx; *.xlsm; *.csv)| *.xls; *.csv; *.xlsx; *.xlsm"
ofdGetOpenFileName.FilterIndex = 2
ofdGetOpenFileName.RestoreDirectory = True
'If the user presses Cancel on the box, warn that no
'file has been selected and the workbook will close
If ofdGetOpenFileName.ShowDialog() = System.Windows.Forms.DialogResult.Cancel Then
'Message box variables
Dim msbContinue As MsgBoxResult
Dim strAlert As String = ("You have not selected a workbook." & vbNewLine & _
"The project will now close without saving changes")
'Once the user presses OK, close the file and do not save changes
msbContinue = MsgBox(strAlert, MsgBoxStyle.OkOnly + MsgBoxStyle.Critical, "No Workbook Seletected")
xlWB.Close(SaveChanges:=False)
Exit Sub
Else
'If the user does select the file, then import the file
'copy and paste on workbook.
'***Here is where I need to check that strImportFile =n, if it does not warn the user******
strImportFile = ofdGetOpenFileName.FileName
If strImportFile <> GetImportFiles(n) then
msgbox("You have not selected the correct file please try again")
GoTo Retry
End If
xlWBImport = Globals.ThisWorkbook.Application.Workbooks.Open(strImportFile)
xlWBImport.Worksheets(1).Cells.Copy(xlWB.Worksheets(strDestSheetName).Range("A1"))
xlWBImport.Close()
End If
Hope this helps....
Should have also added to this it is advisable to put the GoTo as the result of a query to the user otherwise they can find themselves in an endless loop if they are unable to locate the correct file!
Using VBA. My script moves a file into a directory. If that filename already exists in the target directory, I want the user to be prompted to rename the source file (the one that's being moved) before the move is executed.
Because I want the user to know what other files are in the directory already (so they don't choose the name of another file that's already there), my idea is to open a FileDialog box listing the contents of the directory, so that the user can use the FileDialog box's native renaming capability. Then I'll loop that FileDialog until the source file and target file names are no longer the same.
Here's some sample code:
Sub testMoveFile()
Dim fso As FileSystemObject
Dim file1 As File
Dim file2 As File
Dim dialog As FileDialog
Set fso = New FileSystemObject
fso.CreateFolder "c:\dir1"
fso.CreateFolder "c:\dir2"
fso.CreateTextFile "c:\dir1\test.txt"
fso.CreateTextFile "c:\dir2\test.txt"
Set file1 = fso.GetFile("c:\dir1\test.txt")
Set file2 = fso.GetFile("c:\dir2\test.txt")
Set dialog = Application.FileDialog(msoFileDialogOpen)
While file1.Name = file2.Name
dialog.InitialFileName = fso.GetParentFolderName(file2.Path)
If dialog.Show = 0 Then
Exit Sub
End If
Wend
file1.Move "c:\dir2\" & file1.Name
End Sub
But when I rename file2 and click 'OK', I get an error:
Run-time error '53': File not found
and then going into the debugger shows that the value of file2.name is <File not found>.
I'm not sure what's happening here--is the object reference being lost once the file's renamed? Is there an easier way to let the user rename from a dialog that shows all files in the target directory? I'd also like to provide a default new name for the file, but I can't see how I'd do that using this method.
edit: at this point I'm looking into making a UserForm with a listbox that gets populated w/ the relevant filenames, and an input box with a default value for entering the new name. Still not sure how to hold onto the object reference once the file gets renamed, though.
Here's a sample of using Application.FileDialog to return a filename that the user selected. Maybe it will help, as it demonstrates getting the value the user provided.
EDIT: Modified to be a "Save As" dialog instead of "File Open" dialog.
Sub TestFileDialog()
Dim Dlg As FileDialog
Set Dlg = Application.FileDialog(msoFileDialogSaveAs)
Dlg.InitialFileName = "D:\Temp\Testing.txt" ' Set suggested name for user
' This could be your "File2"
If Dlg.Show = -1 Then
Dim s As String
s = Dlg.SelectedItems.Item(1) ` Note that this is for single-selections!
Else
s = "No selection"
End If
MsgBox s
End Sub
Edit two: Based on comments, I cobbled together a sample that appears to do exactly what you want. You'll need to modify the variable assignments, of course, unless you're wanting to copy the same file from "D:\Temp" to "D:\Temp\Backup" over and over. :)
Sub TestFileMove()
Dim fso As FileSystemObject
Dim SourceFolder As String
Dim DestFolder As String
Dim SourceFile As String
Dim DestFile As String
Set fso = New FileSystemObject
SourceFolder = "D:\Temp\"
DestFolder = "D:\Temp\Backup\"
SourceFile = "test.txt"
Set InFile = fso.GetFile(SourceFolder & SourceFile)
DestFile = DestFolder & SourceFile
If fso.FileExists(DestFile) Then
Dim Dlg As FileDialog
Set Dlg = Application.FileDialog(msoFileDialogSaveAs)
Dlg.InitialFileName = DestFile
Do While True
If Dlg.Show = 0 Then
Exit Sub
End If
DestFile = Dlg.Item
If Not fso.FileExists(DestFile) Then
Exit Do
End If
Loop
End If
InFile.Move DestFile
End Sub
Here's some really quick code that I knocked up but basically looks at it from a different angle. You could put a combobox on a userform and get it to list the items as the user types. Not pretty, but it's a start for you to make more robust. I have hardcoded the directory c:\ here, but this could come from a text box
Private Sub ComboBox1_KeyUp(ByVal KeyCode As MSForms.ReturnInteger,
ByVal Shift As Integer)
Dim varListing() As Variant
Dim strFilename As String
Dim strFilePart As String
Dim intFiles As Integer
ComboBox1.MatchEntry = fmMatchEntryNone
strFilePart = ComboBox1.Value
strFilename = Dir("C:\" & strFilePart & "*.*", vbDirectory)
Do While strFilename <> ""
intFiles = intFiles + 1
ReDim Preserve varListing(1 To intFiles)
varListing(intFiles) = strFilename
strFilename = Dir()
Loop
On Error Resume Next
ComboBox1.List() = varListing
On Error GoTo 0
ComboBox1.DropDown
End Sub
Hope this helps. On error resume next is not the best thing to do but in this example stops it erroring if the variant has no files