I'm working on an Access database in which I import csv files converted from xls
Usually this works, but recently one file has some fields where characters change within the field after being imported into Access
For example:
a dash changes to û
a beginning double quote changes to ô
an end double quote changes to ö
From what I have read it has something to do with 7 or 8 bit character codes.. which is not something I really understand.
My questions are, is there any way to prevent this character change or is there something better than what I've tried already?
Or are there any potential problems that I haven't come across with what seems to work in my example below?
Here's what I've tried so far that seems to work
From the original Excel file Save as unicode text file (something new for me)
ActiveWorkbook.SaveAs Filename:= _
"D:\NewFiles\ReportList.txt", FileFormat:=xlUnicodeText _
, CreateBackup:=False
Then import into the database with the following code
DoCmd.TransferText acImportDelim, "ReportList Import Specification", "tbl_ReportList", "D:\NewFiles\ReportList.txt", True
This seems to import the text into the database correctly.
Other people work with the data and then export a new report from Access to Excel.
That changes the font to MS Sans Serif and changes the characters again but not the same changes as when it was imported.
After the Excel report is exported, and I change the font to Arial the characters are correct again.... at least so far.
I haven't run into this character change in the past and my solution seems to work, but I'm not sure if there are other potential problems or if there's anything I missed. I haven't found the answer to this specific question yet.
Thanks for taking time to help with this.
Here is a method that I have used in the past to circumvent the character encoding issues.
I suspect this method should also work between Excel and Access -- although Access is not really something I am familiar with.
This sub specifies the file's full name & path, and a destination for a new filename & path. These could be the same if you want to overwrite existing.
NOTE On a few simple tests, I can't get this to read a file saved as "Unicode" from Excel, but it works perfectly on files saved as "Tab Delimited TXT" files and CSV/comma-separated files, too.
Sub OpenAndSaveTxtUTF8()
Dim txtFileName as String
Dim newTxtFileName as String
txtFileName = "D:\NewFiles\ReportList.txt"
newTxtFileName = "D:\NewFiles\UTF8_ReportList.txt"
WriteUTF8(ReadTextFile(txtFileName), newTxtFileName)
End Sub
This sub calls on two functions which I borrowed from sources credited in the code comments. The WriteUTF8 creates a proper UTF8 file from the contents of ReadTextFile which returns a string of the full file contents.
Function ReadTextFile(sFileName As String) As String
'http://www.vbaexpress.com/kb/getarticle.php?kb_id=699
Dim iFile As Integer
On Local Error Resume Next
' \\ Use FreeFile to supply a file number that is not already in use
iFile = FreeFile
' \\ ' Open file for input.
Open sFileName For Input As #iFile
' \\ Return (Read) the whole content of the file to the function
ReadTextFile = Input$(LOF(iFile), iFile)
Close #iFile
On Error GoTo 0
End Function
This function requires a reference to the ADODB library, or, you can Dim objStream As Object and the code should still work for you.
Function WriteUTF8(textString$, myFileOut$)
'Modified from http://www.vbaexpress.com/forum/showthread.php?t=42375
'David Zemens - February 12, 2013
'Requires a reference to ADODB?
' UTF8() Version 1.00
' Open a "plain" text file and save it again in UTF-8 encoding
' (overwriting an existing file without asking for confirmation).
'
' Based on a sample script from JTMar:
' http://bytes.com/groups/asp/52959-save-file-utf-8-format-asp-vbscript
'
' Written by Rob van der Woude
' http://www.robvanderwoude.com
Dim objStream As ADODB.Stream
' Valid Charset values for ADODB.Stream
Const CdoBIG5 = "big5"
Const CdoEUC_JP = "euc-jp"
Const CdoEUC_KR = "euc-kr"
Const CdoGB2312 = "gb2312"
Const CdoISO_2022_JP = "iso-2022-jp"
Const CdoISO_2022_KR = "iso-2022-kr"
Const CdoISO_8859_1 = "iso-8859-1"
Const CdoISO_8859_2 = "iso-8859-2"
Const CdoISO_8859_3 = "iso-8859-3"
Const CdoISO_8859_4 = "iso-8859-4"
Const CdoISO_8859_5 = "iso-8859-5"
Const CdoISO_8859_6 = "iso-8859-6"
Const CdoISO_8859_7 = "iso-8859-7"
Const CdoISO_8859_8 = "iso-8859-8"
Const CdoISO_8859_9 = "iso-8859-9"
Const cdoKOI8_R = "koi8-r"
Const cdoShift_JIS = "shift-jis"
Const CdoUS_ASCII = "us-ascii"
Const CdoUTF_7 = "utf-7"
Const CdoUTF_8 = "utf-8"
' ADODB.Stream file I/O constants
Const adTypeBinary = 1
Const adTypeText = 2
Const adSaveCreateNotExist = 1
Const adSaveCreateOverWrite = 2
On Error Resume Next
Set objStream = CreateObject("ADODB.Stream")
objStream.Open
objStream.Type = adTypeText
objStream.Position = 0
objStream.Charset = CdoUTF_8
'We are passing a string to write to file, so omit the following line
' objStream.LoadFromFile myFileIn
'And instead of using LoadFromFile we are writing directly from the COPIED
' text from the unsaved/temp instance of Notepad.exe
objStream.WriteText textString, 1
objStream.SaveToFile myFileOut, adSaveCreateOverWrite
objStream.Close
Set objStream = Nothing
If Err Then
WriteUTF8 = False
Else
WriteUTF8 = True
End If
On Error GoTo 0
End Function
Related
I have a one dimensional array with more than 3 million items and I would like to transfer it to a text file. I tried a FileSystemObject method, which is not fast enough for me. So I tried to write to cells in a worksheet and export it as txt file, but I am still searching for a faster way to write an array to a txt file.
Please try also Put (and maybe later also Get):
Private Sub TestPut(myArray() as string)
Dim handle As Long
handle = FreeFile
Open Application.Defaultfilepath & "\Whatever.txt" For Binary As #handle
Put #handle, , myArray
Close #handle
End Sub
You may join your array as a single string to prevent unwanted descriptors (see above Put-documentation) and to define CR or CRLF or whatever as delimiter,
but only if the resulting string's length does not exceed 2,147,483,647 bytes:
Put #handle, , Join(myArray, vbCrLf)
Try something like that
FilePath = "C:\output.txt"
Set FileStream = CreateObject("ADODB.Stream")
FileStream.Open
FileStream.Type = 2 'Text
FileStream.Charset = "utf-8"
FileStream.WriteText vba.Strings.Join(YourArray)
FileStream.SaveToFile (FilePath)
FileStream.Close
I am developing a website on VisualStudio using VB. In one section of my site I make a DataBase Query, store the result in a DataTable and display it. I give the user the option of dowloading the information, what I would like to do is to download an XLS file to the client's side with the information in the datatable without creating the xls on the server side.
I currently have the following code section to send the file to the user
Dim fileToDownload = Server.MapPath("~/docs/QuejometroVF.pdf")
Response.ContentType = "application/octet-stream"
Dim cd = New ContentDisposition()
cd.Inline = False
cd.FileName = Path.GetFileName(fileToDownload)
Response.AppendHeader("Content-Disposition", cd.ToString())
Dim fileData = System.IO.File.ReadAllBytes(fileToDownload)
Response.OutputStream.Write(fileData, 0, fileData.Length)
But it requires a path to a local file in order to send it.
First I would like to know how to create a xls file from the datatable (only in memory) and then send that object as a file to the client's computer. If it is not possible, Could you tell me how to write the xls file in my server so I can then send it using the code above? I have not really figured out how to do it yet.
I was thinking on doint it that way because I don't want to keep files in the server when I already have that information on the database and I don't pretend on keeping that file stored.
Thank you
I export data to xls file using the following code, my backend is an Oracle database and that's where I get the data:
Dim MyConnection As OracleConnection = OpenConnection(Session("USERNAME"), Session("PASSWORD"))
Dim MyDataSet As New DataSet
MyDataSet = GetExportData(MyConnection, Session("UserDataKey"), Session("CompoundKey"), Session("LastOfCompoundKey"))
'I rename the dataset's table columns to what I want in the xls file
MyDataSet.Tables!data.Columns(0).ColumnName = "IDNumber"
MyDataSet.Tables!data.Columns(1).ColumnName = "FirstName"
MyDataSet.Tables!data.Columns(2).ColumnName = "LastName"
MyDataSet.Tables!data.Columns(3).ColumnName = "Address"
MyDataSet.Tables!data.Columns(4).ColumnName = "City"
MyDataSet.Tables!data.Columns(5).ColumnName = "State"
MyDataSet.Tables!data.Columns(6).ColumnName = "ZipCode"
MyDataSet.Tables!data.Columns(7).ColumnName = "Phone_Area"
MyDataSet.Tables!data.Columns(8).ColumnName = "Phone_Prefix"
MyDataSet.Tables!data.Columns(9).ColumnName = "Phone_Suffix"
MyDataSet.Tables!data.Columns(10).ColumnName = "Email"
MyDataSet.Tables!data.Columns(11).ColumnName = "BirthDay"
Response.ClearContent()
'I create the filename I want the data to be saved to and set up the response
Response.AddHeader("content-disposition", "attachment; filename=" & Replace(Session("Key0"), " ", "-") & "-" & Session("Key1") & "-" & Replace(Replace(Trim(Session("Key2")), ".", ""), " ", "-") & ".xls")
Response.ContentType = "application/excel"
Response.Charset = ""
EnableViewState = False
Dim tw As New System.IO.StringWriter
Dim hw As New System.Web.UI.HtmlTextWriter(tw)
'Create and bind table to a datagrid
Dim dgTableForExport As New DataGrid
If MyDataSet.Tables.Count > 0 Then
If MyDataSet.Tables(0).Rows.Count > 0 Then
dgTableForExport.DataSource = MyDataSet.Tables(0) ' .DefaultView
dgTableForExport.DataBind()
'Finish building response
Dim strStyle As String = "<style>.text { mso-number-format:\#; } </style>"
For intTemp As Integer = 0 To MyDataSet.Tables(0).Rows.Count - 1
For intTemp2 As Integer = 0 To MyDataSet.Tables(0).Columns.Count - 1
dgTableForExport.Items(intTemp).Cells(intTemp2).Attributes.Add("class", "text")
Next
Next
End If
End If
dgTableForExport.RenderControl(hw)
Response.Write(style)
' Write the HTML back to the browser.
Response.Write(tw.ToString())
Response.End()
'Close, clear and dispose
MyConnection.Close()
MyConnection.Dispose()
MyConnection = Nothing
I copied and pasted this from one of my projects, it's untested and may contain error but should get you started.
You can use a MemoryStream or to write the file to Response stream using Response.Write method.
Creating an excel file from a data table is fairly easy as you can just create a GridView and bind the table to it.
Here is a code snippet that does what you need.
Public Sub DownloadExcel(outputTable as System.Data.DataTable)
Dim gv As New GridView
Dim tw As New StringWriter
Dim hw As New HtmlTextWriter(tw)
Dim sheetName As String = "OutputFilenameHere"
gv.DataSource = outputTable
gv.DataBind()
gv.RenderControl(hw)
Response.AddHeader("content-disposition", "attachment; filename=" & sheetName & ".xls")
Response.ContentType = "application/octet-stream"
Response.Charset = ""
EnableViewState = False
Response.Write(tw.ToString)
Response.End()
End Sub
There are a few issues with this method:
This doesn't output a native excel file. Instead, it outputs the HTML for a GridView that Excel will detect and notify the user that the content doesn't match the extension. However, it WILL display in Excel correctly if the user selects 'Yes' from the dialog box.
Earlier versions of Firefox and Chrome didn't like this method and instead download the file with a .html extension. I just tested it in both browsers and it worked with the most up to date versions.
Ideally, you should probably use Excel on your webserver to create native spreadsheets, but this will work if you (like me) don't have the means to do so.
I'm creating a web page that will allow user to upload files to the server.
I was able to save the file on the server, but I notice that the office files (e.g. word, excel) are corrupted and can not be opened.
My UI is fairly simple
<form method="post" enctype="multipart/form-data" action="uploadFile.asp">
<p>Select a file:<br><input type=File size=30 name="file1"></p>
<input type=submit value="Upload">
</form>
In my uploadFile.asp, I'm using VBScript. I tried to read and write the binary data and write it directly.
Function SaveBinaryData(FileName, ByteArray)
Const adTypeBinary = 1
Const adSaveCreateOverWrite = 2
'Create Stream object
Dim BinaryStream
Set BinaryStream = CreateObject("ADODB.Stream")
'Specify stream type - we want To save binary data.
BinaryStream.Type = adTypeBinary
'Open the stream And write binary data To the object
BinaryStream.Open
BinaryStream.Write ByteArray
'Save binary data To disk
BinaryStream.SaveToFile FileName, adSaveCreateOverWrite
End Function
Dim biData
biData = Request.BinaryRead(Request.TotalBytes)
SaveBinaryData "C:\Uploads\ww.xlsx", biData
Like I mentioned previously, if I upload a excel or word file, the file is corrupted. However, text files will work just fine.
I tried other solutions I found online such as Pure ASP, ShadowUploader, etc, but couldn't find one that work properly, they all result in corrupt file or doesn't upload at all.
How can I get it to work properly so that I can upload binary files such as microsft word or excel?
Any help is appreciated!
the form
<form method="post" action="post.asp" enctype="multipart/form-data">
<input type='file' name='blob' size='80' />
</form>
Then the code of post.asp. First of all asp binary code:
Dim folder
folder = "public"
Response.Expires=0
Response.Buffer = TRUE
Response.Clear
Sub BuildUploadRequest(RequestBin)
PosBeg = 1
PosEnd = InstrB(PosBeg,RequestBin,getByteString(chr(13)))
boundary = MidB(RequestBin,PosBeg,PosEnd-PosBeg)
boundaryPos = InstrB(1,RequestBin,boundary)
Do until (boundaryPos=InstrB(RequestBin,boundary & getByteString("--")))
Dim UploadControl
Set UploadControl = CreateObject("Scripting.Dictionary")
'Get an object name
Pos = InstrB(BoundaryPos,RequestBin,getByteString("Content-Disposition"))
Pos = InstrB(Pos,RequestBin,getByteString("name="))
PosBeg = Pos+6
PosEnd = InstrB(PosBeg,RequestBin,getByteString(chr(34)))
Name = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))
PosFile = InstrB(BoundaryPos,RequestBin,getByteString("filename="))
PosBound = InstrB(PosEnd,RequestBin,boundary)
If PosFile<>0 AND (PosFile<PosBound) Then
PosBeg = PosFile + 10
PosEnd = InstrB(PosBeg,RequestBin,getByteString(chr(34)))
FileName = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))
nomefile=filename
UploadControl.Add "FileName", FileName
Pos = InstrB(PosEnd,RequestBin,getByteString("Content-Type:"))
PosBeg = Pos+14
PosEnd = InstrB(PosBeg,RequestBin,getByteString(chr(13)))
ContentType = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))
UploadControl.Add "ContentType",ContentType
PosBeg = PosEnd+4
PosEnd = InstrB(PosBeg,RequestBin,boundary)-2
Value = MidB(RequestBin,PosBeg,PosEnd-PosBeg)
Else
Pos = InstrB(Pos,RequestBin,getByteString(chr(13)))
PosBeg = Pos+4
PosEnd = InstrB(PosBeg,RequestBin,boundary)-2
Value = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))
End If
UploadControl.Add "Value" , Value
UploadRequest.Add name, UploadControl
BoundaryPos=InstrB(BoundaryPos+LenB(boundary),RequestBin,boundary)
Loop
End Sub
Function getByteString(StringStr)
For i = 1 to Len(StringStr)
char = Mid(StringStr,i,1)
getByteString = getByteString & chrB(AscB(char))
Next
End Function
Function getString(StringBin)
getString =""
For intCount = 1 to LenB(StringBin)
getString = getString & chr(AscB(MidB(StringBin,intCount,1)))
Next
End Function
byteCount = Request.TotalBytes
RequestBin = Request.BinaryRead(byteCount)
Dim UploadRequest
Set UploadRequest = CreateObject("Scripting.Dictionary")
BuildUploadRequest RequestBin
Then the code to request.item from form
blob = UploadRequest.Item("blob").Item("Value")
Finally the code to save the file in server. I rename the name's file for not duplicating name and I create an univoque name with the mix of date and time.
contentType = UploadRequest.Item("blob").Item("ContentType")
filepathname = UploadRequest.Item("blob").Item("FileName")
filename = Right(filepathname,Len(filepathname)-InstrRev(filepathname,"\"))
value = UploadRequest.Item("blob").Item("Value")
Set ScriptObject = Server.CreateObject("Scripting.FileSystemObject")
arrayFile = split(filename,".")
estensioneFile = arrayFile(UBound(ArrayFile))
namefileuploaded = day(date())& month(date()) & year(date())& hour(time())&minute(time())& second(time())&"a."&estensioneFile
Set MyFile = ScriptObject.CreateTextFile(Server.mappath(folder)&"\"& namefileuploaded)
For i = 1 to LenB(value)
MyFile.Write chr(AscB(MidB(value,i,1)))
Next
MyFile.Close
I don't see how your code would work.
Classic ASP has no way accessing uploaded files like ASP.NET (Request.UploadedFiles) so if you don't use a a COM component then you need to read Request.BinaryStream and parse out the contents, which isn't so easy.
There are several Classic ASP scripts that do this and I would suggest you use one of these. I have used several and haven't had any problems. I suggest you try one of the free ones like: http://freevbcode.com/ShowCode.asp?ID=4596
I have a script that lists all files in a directory, then for each one it will Response.Write the name and how many downloads it has.
I have everything completed, but when I went for a test, the files that have "odd" characters in the name are replace with a ?
I'm guessing, that since some files have foreign languages as there name, and that some have the iPhone emoji icons in the name, that it doesn't recognize it and puts a ? instead, but this is a serious issue since I can't give the correct file name back to the user, then that incorrect name is fed back into the url to download. (Which doesn't work)
Any suggestions?
Edit:
set fs=Server.CreateObject("Scripting.FileSystemObject")
set fo=fs.GetFolder(Server.MapPath("."))
for each file in fo.files
if fs.GetExtensionName(file.Path) = "plist" then
dim tempList, tempName, ...
tempList = split(file.Name, ".")
'Manipulate name and data ...
Response.write(name)
end if
next
The file names themselves have odd characters, and file.Name returns a ? instead of what is actually there.
18アイコン is one example.
Here's some code which works fine for me:
<%# Language="VBScript" CodePage="65001" %><%
Option Explicit
Response.CodePage = 65001
Response.CharSet = "utf-8"
Dim fs, fo, file
Set fs = Server.CreateObject("Scripting.FileSystemObject")
Set fo = fs.GetFolder(Server.MapPath("."))
For Each file In fo.files
If fs.GetExtensionName(file.Path) = "plist" Then
' Do whatever here...
Response.Write file.Name & "<br>"
End If
Next
%>
If you are using any variables that you didn't dimension beforehand, you'll need to remove the Option Explicit; otherwise, VBScript will complain that you didn't dimension them.
Edit: I copy & pasted the wrong code; this code works.
I have an Access table with some Chinese characters that I need to export into a CSV file with UTF-16 encoding. If this is not possible, I could also try exporting the table into an XLS or CSV file, and then convert the encoding to UTF-16.
I have a feeling there is no simple way of doing this using Access and/or Excel and/or VBA, but if there is, I would love to hear it! If not, a solution using Java would be helpful.
I'm sure it would be helpful if I knew what encoding the file was already in. The Chinese characters show up correctly when I export the file to Microsoft Excel 2000, but they do not show up correctly in Microsoft Access. They were originally typed into Microsoft Excel. I think that means they are in Unicode rich text, but I'm not sure.
Thanks much!
I use ADO streams to do this sort of thing. I had to do this for a TON of websites where I was helping them with SEO automation.
http://www.nonhostile.com/howto-convert-byte-array-utf8-string-vb6.asp
' accept a byte array containing utf-8 data
' and convert it to a string
Public Function ConvertStringToUtf8Bytes(ByRef strText As String) As Byte()
Dim objStream As ADODB.Stream
Dim data() As Byte
' init stream
Set objStream = New ADODB.Stream
objStream.Charset = "utf-16"
objStream.Mode = adModeReadWrite
objStream.Type = adTypeText
objStream.Open
' write bytes into stream
objStream.WriteText strText
objStream.Flush
' rewind stream and read text
objStream.Position = 0
objStream.Type = adTypeBinary
objStream.Read 3 ' skip first 3 bytes as this is the utf-8 marker
data = objStream.Read()
' close up and return
objStream.Close
ConvertStringToUtf8Bytes = data
End Function