我正在使用以下代码从S3下载文件。该代码适用于中型到大型文件,但是,对于极小的文件大小(3kb - TXT文件中的一行),下载失败。
//控制器
Option Explicit On
Public Class RichTextBoxPrintCtrl
Inherits RichTextBox
Private Const AnInch As Double = 14.4
<StructLayout(LayoutKind.Sequential)> _
Private Structure RECT
Public Left As Integer
Public Top As Integer
Public Right As Integer
Public Bottom As Integer
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure CHARRANGE
Public cpMin As Integer ' First character of range (0 for start of doc)
Public cpMax As Integer ' Last character of range (-1 for end of doc)
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure FORMATRANGE
Public hdc As IntPtr ' Actual DC to draw on
Public hdcTarget As IntPtr ' Target DC for determining text formatting
Public rc As Rect ' Region of the DC to draw to (in twips)
Public rcPage As Rect ' Region of the whole DC (page size) (in twips)
Public chrg As CHARRANGE ' Range of text to draw (see above declaration)
End Structure
Private Const WM_USER As Integer = &H400
Private Const EM_FORMATRANGE As Integer = WM_USER + 57
Private Declare Function SendMessage Lib "USER32" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wp As IntPtr, ByVal lp As IntPtr) As IntPtr
' Render the contents of the RichTextBox for printing
'Return the last character printed + 1 (printing start from this point for next page)
Public Function Print(ByVal charFrom As Integer, ByVal charTo As Integer, ByVal e As PrintPageEventArgs) As Integer
' Mark starting and ending character
Dim cRange As CHARRANGE
cRange.cpMin = charFrom
cRange.cpMax = charTo
' Calculate the area to render and print
Dim rectToPrint As RECT
rectToPrint.Top = e.MarginBounds.Top * AnInch
rectToPrint.Bottom = e.MarginBounds.Bottom * AnInch
rectToPrint.Left = e.MarginBounds.Left * AnInch
rectToPrint.Right = e.MarginBounds.Right * AnInch
' Calculate the size of the page
Dim rectPage As RECT
rectPage.Top = e.PageBounds.Top * AnInch
rectPage.Bottom = e.PageBounds.Bottom * AnInch
rectPage.Left = e.PageBounds.Left * AnInch
rectPage.Right = e.PageBounds.Right * AnInch
Dim hdc As IntPtr = e.Graphics.GetHdc()
Dim fmtRange As FORMATRANGE
fmtRange.chrg = cRange ' Indicate character from to character to
fmtRange.hdc = hdc ' Use the same DC for measuring and rendering
fmtRange.hdcTarget = hdc ' Point at printer hDC
fmtRange.rc = rectToPrint ' Indicate the area on page to print
fmtRange.rcPage = rectPage ' Indicate whole size of page
Dim res As IntPtr = IntPtr.Zero
Dim wparam As IntPtr = IntPtr.Zero
wparam = New IntPtr(1)
' Move the pointer to the FORMATRANGE structure in memory
Dim lparam As IntPtr = IntPtr.Zero
lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange))
Marshal.StructureToPtr(fmtRange, lparam, False)
' Send the rendered data for printing
res = SendMessage(Handle, EM_FORMATRANGE, wparam, lparam)
' Free the block of memory allocated
Marshal.FreeCoTaskMem(lparam)
' Release the device context handle obtained by a previous call
e.Graphics.ReleaseHdc(hdc)
' Return last + 1 character printer
Return res.ToInt32()
End Function
Private Sub PrintDocument1_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
' Print the content of the RichTextBox. Store the last character printed.
checkPrint = RichTextBoxPrintCtrl1.Print(checkPrint, RichTextBoxPrintCtrl1.TextLength, e)
' Look for more pages
If checkPrint < RichTextBoxPrintCtrl1.TextLength Then
e.HasMorePages = True
Else
e.HasMorePages = False
End If
End Sub
注销小文件:
def download() {
Request request = Request.get(params.int("id"))
response.setContentType("application/octet-stream")
myService.downloadFileFromS3(request.origFileName, response)
}
void downloadFileFromS3(String fileName, HttpServletResponse response) {
String fullFileNameWithExtension = fileName
response.setHeader("Content-disposition", "attachment;filename=${fullFileNameWithExtension}")
InputStream is = getS3Client().getObject(getBucketName(), fullFileNameWithExtension).getObjectContent()
OutputStream outputStream = response.getOutputStream()
byte[] buffer = new byte[1024];
int length
log.info("This is the length: " + length)
while ((length = is.read(buffer)) != -1) {
log.info("Came here with length: " + length)
outputStream.write(buffer, 0, length)
}
is.close()
}
大文件的日志输出:
This is the length: 0
Came here with length: 15
GroovyPagesServlet: "/WEB-INF/grails-app/views/request/download.gsp" not found
因此,对于小文件,它似乎正在寻找This is the length: 0
Came here with length: 1024
Came here with length: 1024
Came here with length: 1024
Came here with length: 1024
Came here with length: 1024
Came here with length: 1024
Came here with length: 1024
Came here with length: 1024
Came here with length: 1024
Came here with length: 1024
Came here with length: 1024
Came here with length: 531
视图。但它不应该寻找那种观点,因为我把东西放在download.gsp
答案 0 :(得分:1)
我认为Joshua Moore的评论可能是正确答案。
但是,我建议稍微重构代码以使其更清洁。
1)首先尝试避免将与Web相关的对象(如请求,响应)传递给服务层。您可以通过让服务层方法返回OutputStream来重构此操作。在服务方法中,您只需创建一个ByteArrayOutputStream,它将保存从S3下载的文件的内容。然后,您将该输出流的内容写入控制器中的var paths []*s3.CompletedPart
for key, val := range upload_out {
//var unique [10000]*s3.CompletedPart //Attempt unique variable names
name := &s3.CompletedPart{ // this only does one
ETag: &val,
PartNumber: &key,
}
paths = append(paths, name)
}
。这样可以更容易地测试并保持代码DRY(即,您现在可以使用此方法从S3下载文件,而无需将文件内容写入响应)。
2)你也应该重命名控制器方法中声明的response.outputStream
变量,因为request
是一个隐式变量。
<强>为MyService 强>
request
<强> myController的强>
def amazonWebService
OutputStream downloadFileFromS3(String filename) {
InputStream inputStream = amazonWebService.getS3("us-east-1").getObject(getBucketName(), filename).getObjectContent()
OutputStream outputStream = new ByteArrayOutputStream()
byte[] buffer = new byte[1024];
int length
log.info("This is the length: " + length)
while ((length = inputStream.read(buffer)) != -1) {
log.info("Came here with length: " + length)
outputStream.write(buffer, 0, length)
}
if (inputStream) inputStream.close()
return outputStream
}