xlsx file corrupted on download when currency format is CHF using exceljs - format

the file is corrupted when using currency symbols like CHF in ExcelJS
// currency symbol is CHF
private formatRow(property: Property): string {
const currencySymbol = getCurrencySymbol(property.propertyCurrency, 'narrow');
return ${currencySymbol}#,##0.00;
}

Related

How to export csv file with shift-jis encoding in laravel?

I am using laravel-excel to export csv file. To export, the code is like below,
return Excel::download(new Export(results,$header), "test.csv");
And the Export.php file is like,
namespace App\AllClass;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithHeadings;
class Export implements FromCollection,WithHeadings
{
private $myArray;
private $header;
public function __construct($myArray,$header){
$this->myArray = $myArray;
$this->header = $header;
}
public function collection()
{
$data = mb_convert_encoding($this->myArray,"SJIS", "UTF-8");
// dump($data);
return collect($data);
}
public function headings(): array
{
$header = mb_convert_encoding($this->header,"SJIS", "UTF-8");
// dump($header);
return $header;
}
}
As you can see, I am converting the data before creating excel. Without converting I can export perfectly in UTF-8 format. But after converting to shift-jis, it is deleting all Japanese character. However, if I dump the header before returning, it is showing me gibberish data; not empty string like the csv file.
I resolved it.
Let's me share my solution here.
Laravel Excel not support it by default.
But we can do it by simple way.
Get csv content before download: \Excel::raw
Convert to another encoding: mb_convert_encoding
https://docs.laravel-excel.com/3.1/exports/collection.html#storing-raw-contents
Download csv.
$exportedObject= new \App\Exports\ClassExport($exportDataArray, $fileName);
$csvContent = \Excel::raw($exportedObject, $exportedObject->writerType);
$csvContent = mb_convert_encoding($csvContent, 'SJIS', 'auto');
// In my case, I upload my csv to S3.
$storageInstance = \Storage::disk('s3_import_csvs');
$putFileOnStorage = $storageInstance->put($fileName, $csvContent);
In config/excel.php, you should change CSV Settings
'use_bom' => true,
It's work well in Japanese

Implementing file attachments in JHipster

I have a monolithic JHipster (v5.6.1) project, and I need to implement file attachments to an entity.
I don't know where to start with this. DTOs are sent to REST controllers to create or update them, how should I send the file?
I could attach the Base64 to my DTO and send it that way, but I'm not sure how (are there any angular plugins to accomplish this?). This would require extra work for the server and, I think, extra file size.
Another option is to send the entity (DTO) and file separately, again I'm not entirely sure how.
I see no reason to leave this question unanswered since I have implemented attachments successfully in several of my projects now.
If you prefer, you can skip this explanation and check the github repository I created at vicpermir/jhipster-ng-attachments. It's a working project ready to fire up and play.
The general idea is to have an Attachment entity with all the required fields (file size, name, content type, etc...) and set a many-to-many relation to any entity you want to implement file attachments for.
The JDL is something like this:
// Test entity, just to showcase attachments, this should
// be the entity you want to add attachments to
entity Report {
name String required
}
entity Attachment {
filename String required // Generated unique filename on the server
originalFilename String required // Original filename on the users computer
extension String required
sizeInBytes Integer required
sha256 String required // Can be useful for duplication and integrity checks
contentType String required
uploadDate Instant required
}
// ManyToMany instead of OneToMany because it will be easier and cleaner
// to integrate attachments into other entities in case we need to do it
relationship ManyToMany {
Report{attachments} to Attachment{reports}
}
I have both filename and originalFilename because one of my requirements was to keep whatever file name the user uploaded it with. The generated unique name that I use on the server side is transparent to the user.
Once you generate a project with a JDL like that, you will have to add the file payload to your DTO (or entity if you don't use DTOs) so that the server can receive it in base64 and store it.
I have this in my AttachmentDTO:
...
private Instant uploadDate;
// File payload (transient)
private byte[] file;
public Long getId() {
return id;
}
...
Then, you only have to process those byte arrays on the server side, store them and save a reference to the location into the database.
AttachmentService.java
/**
* Process file attachments
*/
public Set<AttachmentDTO> processAttachments(Set<AttachmentDTO> attachments) {
Set<AttachmentDTO> result = new HashSet<>();
if (attachments != null && attachments.size() > 0) {
for (AttachmentDTO a : attachments) {
if (a.getId() == null) {
Optional<AttachmentDTO> existingAttachment = this.findBySha256(a.getSha256());
if(existingAttachment.isPresent()) {
a.setId(existingAttachment.get().getId());
} else {
String fileExtension = FilenameUtils.getExtension(a.getOriginalFilename());
String fileName = UUID.randomUUID() + "." + fileExtension;
if (StringUtils.isBlank(a.getContentType())) {
a.setContentType("application/octet-stream");
}
Boolean saved = this.createBase64File(fileName, a.getFile());
if (saved) {
a.setFilename(fileName);
}
}
}
result.add(a);
}
}
return result;
}
What I do here is check if the attachment already exists (using the SHA256 hash). If it does I use that one, otherwise I store the new file and persist the new attachment data.
What's left now is to manage attachments on the client side. I created two components for this so it is extremely easy to add attachments to new entities.
attachment-download.component.ts
...
#Component({
selector: 'jhi-attachment-download',
template: , // Removed to reduce verbosity
providers: [JhiDataUtils]
})
export class JhiAttachmentDownloadComponent {
#Input()
attachments: IAttachment[] = [];
}
This just calls a mapping that takes the attachment ID, looks for the associated file on the server and returns that file for the browser to download. Use this component in your entity detail view with:
<jhi-attachment-download [attachments]="[your_entity].attachments"></jhi-attachment-download>
attachment-upload.component.ts
...
#Component({
selector: 'jhi-attachment-upload',
template: , // Removed to reduce verbosity
providers: [JhiDataUtils]
})
export class JhiAttachmentUploadComponent {
#Input()
attachments: IAttachment[] = [];
loadingFiles: number;
constructor(private dataUtils: JhiDataUtils) {
this.loadingFiles = 0;
}
addAttachment(e: any): void {
this.loadingFiles = 0;
if (e && e.target.files) {
this.loadingFiles = e.target.files.length;
for (let i = 0; i < this.loadingFiles; i++) {
const file = e.target.files[i];
const fileName = file.name;
const attachment: IAttachment = {
originalFilename: fileName,
contentType: file.type,
sizeInBytes: file.size,
extension: this.getExtension(fileName),
processing: true
};
this.attachments.push(attachment);
this.dataUtils.toBase64(file, (base64Data: any) => {
attachment.file = base64Data;
attachment.sha256 = hash
.sha256()
.update(base64Data)
.digest('hex');
attachment.processing = false;
this.loadingFiles--;
});
}
}
e.target.value = '';
}
getExtension(fileName: string): string {
return fileName.substring(fileName.lastIndexOf('.'));
}
}
Use this component in your entity update view with:
<jhi-attachment-upload [attachments]="editForm.get('attachments')!.value"></jhi-attachment-upload>
Once sent to the server, the files will be stored on the folder you configured in your application-*.yml separated in subdirectories by year and month. This is to avoid storing too many files on the same folder, which can be a big headache.
I'm sure many things could be done better, but this has worked for me.

File extension for tab-delimited values that can be opened by Excel?

I'm outputting a tab-delimited file from my webapp that should be opened in Excel. The problem is that .xls seems not good for opening and editing it, then Excel required some other format, and if I change the extension to .tsv then the file becomes unknown for Excel (on Windows 7) and .csv is for comma-separated. Can you advice me which the file extension should be?
This is the code that outputs the file and it works. It's just that I should choose the most suitable extension for tab-separated values.
#RequestMapping(value = "/export", method = RequestMethod.GET)
#ResponseBody
public ModelAndView export(HttpServletResponse response) {
try {
String str = "";
Iterator<Individual> iterator = customerAccountService.getAllIndividuals().iterator();
while(iterator.hasNext()){
Individual individual = iterator.next();
str = str + individual.getId() + "\t" +individual.getIndividualName().getName() + "\t" + individual.getAddress().getStreetName() + "\n";
}
InputStream is = new ByteArrayInputStream(str.getBytes());
IOUtils.copy(is, response.getOutputStream());
response.setContentType("application/xls");
response.setHeader("Content-Disposition","attachment; filename=export.tsv");
response.flushBuffer();
} catch (IOException ex) {
//logger.info("Error writing file to output stream. Filename was '" + fileName + "'");
throw new RuntimeException("IOError writing file to output stream");
}
ModelAndView modelAndView = new ModelAndView(ViewName.MENU);
modelAndView.addObject(ObjectName.ADD_FORM, new LoginForm());
return modelAndView;
}
Put
sep=\t
as the first line in your .csv-file (yes, you can name it .csv then). That tells excel what the delimiter character should be.
Note, that actually if you open the .csv with a text editor, it should read like
sep= (an actual tabulator character here, it's just not visible...)

export chinese, japanese character in .csv file + mvc3

I am using following code to export the content to .cvs file
which also support chinese and japanese characters.
public ActionResult Download(strng accnumber)
{
string csvContent = "东西,东西,东西, hi";
var data = Encoding.UTF32.GetBytes(csvContent );
string filename = "CSV_" + accnumber + ".csv";
return File(data, "text/csv", filename);
}
when i export my file i am not getting proper chinese or japanese characters. what is missing?
i have used UTF32 encoding to support it.
Edited:
i have noticed that opening my .csv file in notepad shows perfect characters but ms-excel doesn't.
I am also got same problem, solve it by using UTF-8-BOM.
Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(stringData)).ToArray()
As you are on asp.net serving that file you also have to deal with the encoding of the http pipleline. I din't spot that earlier, sorry.
Instead of having a plain ActionResult you should use one of the derived ActionResults, I've used FileContentResult. Please pay note to the special ContentType I'm constructing to tell the browsers an UTF-32 file is coming...
public ActionResult Download(string accnumber)
{
string csvContent = "东西,东西,东西, hi";
var data = Encoding.UTF8.GetBytes(csvContent);
// add byte order mark
var bom = new byte[] { 0xEF, 0xBB, 0xBF };
// hold it all
var all = new byte[bom.Length + data.Length];
// copy over BOM
Array.Copy(bom, all, bom.Length);
// copy over data
Array.Copy(data, 0, all, bom.Length, data.Length);
string filename = "CSV_" + accnumber + ".csv";
var file = new FileContentResult( all, "text/csv" )
{
FileDownloadName = filename
};
return file;
}
I encountered this problem too. I fix it by adding the following line just before "return file ;" and it works for me.
Response.Write("<meta http-equiv=Content-Type content=text/html;charset=utf-8>");
return file;

How do I read the Received Date from Outlook MSG files -without- the Outlook API?

I need to read stuff from an Outlook msg file. Currently I'm using a class from CodeProject.com project to accomplish this, since deploying VSTO and Outlook on a server is not an option.
This class gets To, From, CC, Subject, Body, and everything else I need from the msg file, except Date information (such as Received Date and Sent Date).
There is some (really, really low-level) documentation on how to get stuff out of msg files on MSDN, but it's a little beyond the scope of this project and doesn't mention dates at all.
Ideally I'd be able to have a drop-in replacement for the class I am using now (OutlookStorage.cs in the previously mentioned CodeProject) or be able to modify the existing class a bit. To modify, I would need the correct 4 character hexidecimal prop identifier for received date. For instance, Subject is listed as PR_SUBJECT = "0037" and Body is listed as PR_BOY = "1000".
If you're using OutlookStorage.cs from CodeProject, then add the following:
private const string PR_RECEIVED_DATE="007D";
private const string PR_RECEIVED_DATE_2 = "0047";
...
/// <summary>
/// Gets the date the message was received.
/// </summary>
public DateTime ReceivedDate
{
get
{
if (_dateRevieved == DateTime.MinValue)
{
string dateMess = this.GetMapiPropertyString(OutlookStorage.PR_RECEIVED_DATE);
if (String.IsNullOrEmpty(dateMess))
{
dateMess = this.GetMapiPropertyString(OutlookStorage.PR_RECEIVED_DATE_2);
}
_dateRevieved = ExtractDate(dateMess);
}
return _dateRevieved;
//return ExtractDate(dateMess);
}
}
private DateTime _dateRevieved = DateTime.MinValue;
private DateTime ExtractDate(string dateMess)
{
string matchStr = "Date:";
string[] lines = dateMess.Split(new String[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
{
if (line.StartsWith(matchStr))
{
string dateStr = line.Substring(matchStr.Length);
DateTime response;
if (DateTime.TryParse(dateStr, out response))
{
return response;
}
}
}
return DateTime.MinValue;
}
I think the Aspose library will do what you want, ok it a 3rd party lib so may not be what you want. There are a few vbs scripts around that get basic infomation out of msg files that could be translated.
Got a hint from this:
string fullFileName = "c:\message.msg";
DateTime dateRevieved = new DateTime();
StreamReader sr = new StreamReader(fullFileName, Encoding.Default);
string full = sr.ReadToEnd();
string date;
int iStart;
int iLast;
string caption;
//This -should- handle all manner of screwage
//The ONLY way it would not is if someone guessed the -exact- to-the-second
//time that they send the message, put it in their subject in the right format
while (true) { //not an infinite loop, I swear!
caption = "Date:";
if (full.IndexOf("Date:") > -1) { //full shortens with each date is removed
string temp = "";
iStart = full.LastIndexOf(caption);
temp = full.Remove(0, iStart + caption.Length);
full = full.Substring(0, iStart);
iLast = temp.IndexOf("\r\n");
if (iLast < 0) {
date = temp;
} else {
date = temp.Substring(0, iLast);
}
date = date.Trim();
if (date.Contains(subject) || subject.Contains(date)) {
continue; //would only happen if someone is trying to screw me
}
try {
dateRevieved = DateTime.Parse(date); //will fail if not a date
break; //if not a date breaks out of while loop
} catch {
continue; //try with a smaller subset of the msg
}
} else {
break;
}
}
This is kind of a hack compared to the ways you can get other things from msg files using something this lovely project. Still, it's stood up to everything I have thrown against it, and as noted the -only- way to fool it is to put the exact to-the-second date in the subject line in the proper format.
to combine your two posts I would suggest the following solution:
To modify, I would need the correct 4 character hexidecimal prop identifier for recieved date. For instance, Subject is listed as PR_SUBJECT = "0037" and Body is listed as PR_BOY = "1000".
Look for "007D".
Use the method you posted in your second post on the received data to eliminate the problem when the same (date) string is inside the subject.
I have to mention that this method doesn't seem to work on internal eMails: In mails I receive from colleagues, there is no substg1.0_007Dxxxx-Property.
Here, the date seems to be hidden in substg1.0_0047xxxx.
All the best!
inno

Resources