Automatically Generate CSVs based on cell data - vba

I have the following code which generates a csv file.
Sub WriteCSVFile()
Dim My_filenumber As Integer
Dim logSTR As String
My_filenumber = FreeFile
logSTR = logSTR & Cells(1, "A").Value & " , "
logSTR = logSTR & Cells(2, "A").Value & " , "
logSTR = logSTR & Cells(3, "A").Value & " , "
logSTR = logSTR & Cells(4, "A").Value
Open "D:\BIG DATA\VBA\Sample.csv" For Append As #My_filenumber
Print #My_filenumber, logSTR
Close #My_filenumber
End Sub
This just pulls the top 4 values from the sheets and puts them in a CSV, I now need to modify it to do 2 things, one generate multiple CSVs one for each unique value in column A and then pull values from column B based on column A.
For example:-
Column A contains set A, set B, set C - Set A has 3 tables in column B and I want this to be copied across to the new CSV but I want this to happen for all the sets automatically.
Any help would be greatly appreciated, even a point to another answer?

I am assuming that you want to Print the contents of each Table to the associated Set.
Sub WriteCSVFile2()
Const RootPath As String = "C:\Data Files\Sample_"
Const KillOldFiles As Boolean = True
Dim My_filenumber As Integer
Dim FileName As String
Dim rw As Range
Dim tbls As Collection
Dim tbl As ListObject
Set tbls = getAllTables
My_filenumber = FreeFile
If KillOldFiles Then
For Each rw In Sheet1.ListObjects("SourceTable").DataBodyRange.Rows
FileName = RootPath & rw.Cells(1, 1) & ".csv"
If Len(Dir(FileName)) Then Kill FileName
Next
End If
For Each rw In Sheet1.ListObjects("SourceTable").DataBodyRange.Rows
FileName = RootPath & rw.Cells(1, 1) & ".csv"
Debug.Print FileName
On Error Resume Next
Set tbl = tbls.Item(rw.Cells(1, 2))
If Not tbl Is Nothing Then
Open FileName For Append As #My_filenumber
Print #My_filenumber, getDataBodyRangeCSV(tbl)
Close #My_filenumber
End If
Set tbl = Nothing
On Error GoTo 0
Next
End Sub
Function getDataBodyRangeCSV(tbl As ListObject) As String
Dim c As Range, rw As Range
Dim tr As String, result As String
For Each rw In tbl.DataBodyRange.Rows
For Each c In rw.Cells
tr = tr & c.value & ","
Next
result = result & Left(tr, Len(tr) - 1) & vbCrLf
tr = ""
Next
getDataBodyRangeCSV = Left(result, Len(result) - 1)
End Function
Function getAllTables() As Collection
Dim lists As Collection
Dim tbl As ListObject
Dim ws As Worksheet
Set lists = New Collection
For Each ws In ThisWorkbook.Worksheets
For Each tbl In ws.ListObjects
On Error Resume Next
lists.Add tbl, tbl.Name
On Error GoTo 0
Next
Next
Set getAllTables = lists
End Function
Update: You don't need the more complex example but I am going to leave it. It may be helpful to future viewers.
Cahnge these variables
SouceWorkSheet: The name of the worksheet that your list is on
KillOldFiles: Do you want to delete the old files
arColumns = Array(1, 2, 9, 10): Add the column numbers that you want to export to this array. You just nned to use WriteCSVFile3.
Sub WriteCSVFile3()
Const SouceWorkSheet As String = "Source"
Const RootPath As String = "C:\Data Files\Sample_"
Const KillOldFiles As Boolean = True
Dim My_filenumber As Integer
Dim FileName As String, tr As String
Dim lastRow As Long, x As Long, y
Dim arColumns As Variant
arColumns = Array(1, 2, 9, 10)
My_filenumber = FreeFile
With Worksheets(SouceWorkSheet)
lastRow = .Range("A" & Rows.Count).End(xlUp).Row
If KillOldFiles Then
For x = 2 To lastRow
FileName = RootPath & .Cells(x, 1) & ".csv"
If Len(Dir(FileName)) Then Kill FileName
Next
End If
For x = 2 To lastRow
FileName = RootPath & .Cells(x, 1) & ".csv"
Open FileName For Append As #My_filenumber
For y = 0 To UBound(arColumns)
tr = tr & .Cells(x, arColumns(y)).value & ","
Next
Print #My_filenumber, Left(tr, Len(tr) - 1)
Close #My_filenumber
tr = ""
Next
End With
End Sub

Can't you use something like this ?
Dim OutputFileNum As Integer
OutputFileNum = FreeFile
Open "file.csv" For Output Lock Write As #OutputFileNum
Print #OutputFileNum, "Field1" & "," & "Field2"
SheetValues = Sheets("Sheet1").Range("A1:H9").Value
Dim LineValues() As Variant
ReDim LineValues(1 To 2)
For RowNum = 1 To 9
For ColNum = 1 To 2
LineValues(ColNum) = SheetValues(RowNum, ColNum)
Next
Line = Join(LineValues, ",")
Print #OutputFileNum, Line
Next
Close OutputFileNum

Related

VBA to export selected row values of excel to csv

I have a requirement for VBA, wherein, If I select a cell in excel, it will export that entire row values to csv.
I have tried
Sub WriteCSVFile()
Dim My_filenumber As Integer
Dim logSTR As String
My_filenumber = FreeFile
logSTR = logSTR & Cells(1, "A").Value & " , "
logSTR = logSTR & Cells(2, "A").Value & " , "
logSTR = logSTR & Cells(3, "A").Value & " , "
logSTR = logSTR & Cells(4, "A").Value
Open "C:\Users\xxxxx\Desktop\Sample.csv" For Append As #My_filenumber
Print #My_filenumber, logSTR
Close #My_filenumber
End Sub
If the range selection can be made dynamic, it can solve the purpose.
Export Selection Rows to CSV
Sub ExportRowsToCSV()
Const FILE_PATH_RIGHT As String = "\Desktop\Sample.csv"
Const FIRST_CELL_ADDRESS As String = "A2"
Const ColDelimiter As String = "," ' or ";"
Const RowDelimiter As String = vbLf
If ActiveSheet Is Nothing Then Exit Sub ' no visible workbook open
If Not TypeOf ActiveSheet Is Worksheet Then Exit Sub ' not a worksheet
If Not TypeOf Selection Is Range Then Exit Sub ' not a range selected
Dim FilePath As String
FilePath = Environ("USERPROFILE") & FILE_PATH_RIGHT
' or:
'FilePath = Environ("OneDrive") & FILE_PATH_RIGHT
Dim drg As Range: Set drg = Selection
Dim ws As Worksheet: Set ws = drg.Worksheet
Dim srg As Range
With ws.UsedRange
Dim lCell As Range: Set lCell = .Cells(.Rows.Count, .Columns.Count)
Set srg = ws.Range(FIRST_CELL_ADDRESS, lCell)
End With
Dim rg As Range: Set rg = Intersect(srg, drg)
If rg Is Nothing Then Exit Sub
Set rg = Intersect(srg, rg.EntireRow)
If rg Is Nothing Then Exit Sub
Dim dLen As Long: dLen = Len(ColDelimiter)
Dim rString As String
Dim rrg As Range
Dim cell As Range
For Each rrg In rg.Rows
For Each cell In rrg.Cells
rString = rString & CStr(cell.Value) & ColDelimiter
Next cell
rString = Left(rString, Len(rString) - dLen) & RowDelimiter
Next rrg
rString = Left(rString, Len(rString) - Len(RowDelimiter))
Dim TextFile As Long: TextFile = FreeFile
Open FilePath For Append As #TextFile
Print #TextFile, rString
Close #TextFile
MsgBox "Row(s) exported.", vbInformation
End Sub
Here I got the code to copy the "values in the entire row where the cell is active" and paste to csv file.
'''
Sub xlRangeToCSVFile()
Dim myWB As Workbook
Dim rngToSave As Range
Dim fNum As Integer
Dim csvVal As String
Dim i As Integer
Set myWB = ThisWorkbook
csvVal = ""
fNum = FreeFile
Set rngToSave = Range("A" & ActiveCell.Row & ":J" & ActiveCell.Row)
Open "C:\Users\xxxxx\Desktop\Sample.csv" For Output As #fNum
i = 1
For j = 1 To rngToSave.Columns.Count
csvVal = csvVal & Chr(34) & rngToSave(i, j).Value & Chr(34) & ","
Next
Print #fNum, Left(csvVal, Len(csvVal) - 1)
csvVal = ""
Close #fnum
End Sub
'''

VBA code:Save the fillter data to txt file

VBA code: help me with, I want to save the fillter data to txt file.
Sub Intemp()
Dim arr, i As Long
Dim FPath As String
FPath = ThisWorkbook.Path & "\" & "text" & ".txt"
Application.CutCopyMode = False
arr = Sheet5.Range("B1:C" & [B100000].End(xlUp).Row)
Open FPath For Output As #1
For i = 1 To UBound(arr)
Print #1, arr(i, 1) & vbTab & arr(i, 2)
Next i
Close #1
End Sub
If you want to assign your filtered values to an array, an easy way to do that would be to use advanced filtering and filter into another area of the worksheet and assign your values there.
But a simple approach that will get you started is to just loop your rows in your range, if the row is hidden, then move on - otherwise, print the data to your text document.
Dim rng As Range, r As Long
Set rng = Sheet5.Range("B1:C" & [B100000].End(xlUp).Row)
Dim FPath As String
FPath = ThisWorkbook.Path & "\" & "text" & ".txt"
Application.CutCopyMode = False
Open FPath For Output As #1
With Sheet5
For r = rng.Row To rng.Rows.Count + rng.Row - 1
If Not .Rows(r).Hidden Then
Print #1, .Cells(r, 1) & vbTab & .Cells(r, 2)
End If
Next
End With
Close #1

How To Create Text File From Excel Values

Im currently working on a tool that will enable me to create my specific profile for entries present in my Excel File.
Assuming that I have these values:
Male:
And I want to generate a text file like this one below. There must be separate filename for both female and male and one file per row only.
I currently have this code below:
Sub toFile()
Dim FilePath As String, CellData As String, LastCol As Long, LastRow As Long
Dim Filenum As Integer
LastCol = ActiveSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Column
LastRow = ActiveSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Row
For i = 1 To LastRow
FilePath = Application.DefaultFilePath & "\" & Trim(ActiveSheet.Cells(i, 1).Value) & ".xpd"
Filenum = FreeFile
Open FilePath For Output As Filenum
CellData = ""
For j = 2 To LastCol
CellData = Trim(ActiveSheet.Cells(i, j).Value)
Write #Filenum, CellData
Next j
Close #Filenum
Next i
MsgBox ("Done")
End Sub
Sample Output of this code:
How can I achieve my expected output mentioned above?
Here is the final code which will create two files and won't write values where cells are blank:
Sub toFile()
Dim FilePath As String, CellData As String, LastCol As Long, LastRow As Long
Dim Filenum As Integer
LastCol = ActiveSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Column
LastRow = ActiveSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Row
For i = 2 To LastRow
FilePath = Application.DefaultFilePath & "\" & Trim(ActiveSheet.Cells(i, 1).Value) & ".TXT"
Filenum = FreeFile
Open FilePath For Output As Filenum
CellData = ""
For j = 2 To LastCol
If Trim(ActiveSheet.Cells(i, j).Value) <> "" Then
CellData = Trim(ActiveSheet.Cells(1, j).Value) & ": " & Trim(ActiveSheet.Cells(i, j).Value)
Write #Filenum, CellData
End If
Next j
Close #Filenum
Next i
MsgBox ("Done")
End Sub
Use the below code
Change the code
For i = 2 To LastRow
and
celldata = Trim(ActiveSheet.Cells(1, j)) & ": " & Trim(ActiveSheet.Cells(i, j).Value)

vba define range ending text

I'm trying to process a data file and export each section to a separate text file. I can specify a range to export without issue (A1:A58) but I never know how many lines I'll need so it should be dynamic. For example, sheet1 will export 58 rows because row 1 will always start the range (A1) and 58 (A58) contains the text "Referring" indicating the end of that record. Then, those rows will be deleted. The next record will start with specific text "NewRecord" (A1) and complete with the words "Referring" again.
Sub ExportRange()
Dim c As Range, r As Range
Dim output As String
Dim MyFolder As String
Dim MyFile As String
Dim i As Long
Dim MyOldFile As String
Dim MyNewFile As String
MyFolder = "C:\Users\profile\Documents\test"
MyFile = Dir(MyFolder & "\text.txt")
i = i + 1
MyOldFile = MyFolder & "\" & MyFile
MyNewFile = MyFolder & "\" & Sheets("Sheet1").Range("B20") & "_" & i & ".txt"
For Each r In Range("A1:A37").Rows
For Each c In r.Cells
output = output & "," & c.Value
Next c
output = output & vbNewLine
Next r
Open "C:\Users\profile\Documents\test\Text.txt" For Output As #1
Print #1, output
Close
Name MyOldFile As MyNewFile
MyFile = Dir
Close
End Sub
This will find the first row that contains "Referring" searching from the top down and create a range from it that is used in the For loop.
Sub ExportRange()
Dim c As Range, r As Range, LoopRange as Range
Dim output As String
Dim MyFolder As String
Dim MyFile As String
Dim i As Long
Dim MyOldFile As String
Dim MyNewFile As String
Set LoopRange = Range("A1", Cells(Range("A:A").Find(what:="Referring", after:=Range("A1"), searchdirection:=xlNext).Row, "A"))
MyFolder = "C:\Users\profile\Documents\test"
MyFile = Dir(MyFolder & "\text.txt")
i = i + 1
MyOldFile = MyFolder & "\" & MyFile
MyNewFile = MyFolder & "\" & Sheets("Sheet1").Range("B20") & "_" & i & ".txt"
For Each r In LoopRange.Rows
For Each c In r.Cells
output = output & "," & c.Value
Next c
output = output & vbNewLine
Next r
Open "C:\Users\profile\Documents\test\Text.txt" For Output As #1
Print #1, output
Close
Name MyOldFile As MyNewFile
MyFile = Dir
Close
End Sub

How to execute this Excel to XML function in a sub?

Can someone assist with how I can use this function below that converts my data in an excel file to an XML file in a sub? When I go to create a macro it by default has it for sub but I need to have it as a function. I need to be able to use this as maybe a custom button on the toolbar possibly or how can I use it for any spreadsheet I need to convert it from Excel to an XML file?
Public Function ExportToXML(FullPath As String, RowName _
As String) As Boolean
On Error GoTo ErrorHandler
Dim colIndex As Integer
Dim rwIndex As Integer
Dim asCols() As String
Dim oWorkSheet As Worksheet
Dim sName As String
Dim lCols As Long, lRows As Long
Dim iFileNum As Integer
Set oWorkSheet = ThisWorkbook.Worksheets(1)
sName = oWorkSheet.Name
lCols = oWorkSheet.Columns.Count
lRows = oWorkSheet.Rows.Count
ReDim asCols(lCols) As String
iFileNum = FreeFile
Open FullPath For Output As #iFileNum
For i = 0 To lCols - 1
'Assumes no blank column names
If Trim(Cells(1, i + 1).Value) = "" Then Exit For
asCols(i) = Cells(1, i + 1).Value
Next i
If i = 0 Then GoTo ErrorHandler
lCols = i
Print #iFileNum, "<?xml version=""1.0""?>"
Print #iFileNum, "<" & sName & ">"
For i = 2 To lRows
If Trim(Cells(i, 1).Value) = "" Then Exit For
Print #iFileNum, "<" & RowName & ">"
For j = 1 To lCols
If Trim(Cells(i, j).Value) <> "" Then
Print #iFileNum, " <" & asCols(j - 1) & "><![CDATA[";
Print #iFileNum, Trim(Cells(i, j).Value);
Print #iFileNum, "]]></" & asCols(j - 1) & ">"
DoEvents 'OPTIONAL
End If
Next j
Print #iFileNum, " </" & RowName & ">"
Next i
Print #iFileNum, "</" & sName & ">"
ExportToXML = True
ErrorHandler:
If iFileNum > 0 Then Close #iFileNum
Exit Function
End Function
To convert to a Sub that could be run from a button you would change it to:
Public Sub ExportToXML()
This will automatically change the last line to End Sub.
FullPath and RowName will no longer be passed as function-arguments, so would, presumably, need to be read from cells on a worksheet, or perhaps from two InputBoxes.
The Sub would no longer return a Boolean value, so whatever happens with this value would have to be converted to code within the same Sub (or possibly passed to another Sub).