使用 Graph API 将文件(> 4MB)上传到 OneDrive
Upload file (> 4MB) to OneDrive using Graph API
我正在尝试使用 Graph API 将文件上传到 OneDrive。当我上传小于 4MB 的文件时,下面的代码工作正常,但当我尝试上传大于 4MB 的文件时,它显示错误。我经历了 this documentation 但我仍然不确定如何才能完成这项工作。
下面是我对小于 4MB 的文件的工作代码。
using (var client = new HttpClient())
{
var url = "https://graph.microsoft.com/v1.0" + $"/drives/{driveID}/items/{folderId}:/{originalFileName}:/content";
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());
byte[] sContents = System.IO.File.ReadAllBytes(filePath);
var content = new ByteArrayContent(sContents);
var response = client.PutAsync(url, content).Result.Content.ReadAsStringAsync().Result;
}
请帮忙
对于大于 4MB 的文件,您需要 create an uploadSession 您 POST 此 URL:
https://graph.microsoft.com/v1.0/me/drive/root:/{item-path}:/createUploadSession
传递一组项目,
{
"item": {
"@odata.type": "microsoft.graph.driveItemUploadableProperties",
"@microsoft.graph.conflictBehavior": "rename",
"name": "largefile.dat"
}
}
我用的是"@microsoft.graph.conflictBehavior": "overwrite"
,而不是rename
。
响应会提供上传url批量上传文件
{
"uploadUrl": "https://sn3302.up.1drv.com/up/fe6987415ace7X4e1eF866337",
"expirationDateTime": "2015-01-29T09:21:55.523Z"
}
我没有 C# 示例,但这里有一个 PHP:
$url = $result['uploadUrl'];
$fragSize = 1024*1024*4;
$file = file_get_contents($source);
$fileSize = strlen($file);
$numFragments = ceil($fileSize / $fragSize);
$bytesRemaining = $fileSize;
$i = 0;
$response = null;
while ($i < $numFragments) {
$chunkSize = $numBytes = $fragSize;
$start = $i * $fragSize;
$end = $i * $fragSize + $chunkSize - 1;
$offset = $i * $fragSize;
if ($bytesRemaining < $chunkSize) {
$chunkSize = $numBytes = $bytesRemaining;
$end = $fileSize - 1;
}
if ($stream = fopen($source, 'r')) {
// get contents using offset
$data = stream_get_contents($stream, $chunkSize, $offset);
fclose($stream);
}
$contentRange = " bytes " . $start . "-" . $end . "/" . $fileSize;
$headers = array(
"Content-Length: $numBytes",
"Content-Range: $contentRange"
);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$server_output = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
$bytesRemaining = $bytesRemaining - $chunkSize;
$i++;
}
我们需要按长度(即 4MB)拆分字节数组并将它们传递给 OneDrive API。工作版本如下:
using (var client = new HttpClient())
{
var url = "https://graph.microsoft.com/v1.0" + $"/drives/{driveID}/items/{folderId}:/{originalFileName}:/createUploadSession";
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());
var sessionResponse = client.PostAsync(apiUrl, null).Result.Content.ReadAsStringAsync().Result;
byte[] sContents = System.IO.File.ReadAllBytes(filePath);
var uploadSession = JsonConvert.DeserializeObject<UploadSessionResponse>(sessionResponse);
string response = UploadFileBySession(uploadSession.uploadUrl, sContents);
}
UploadFileBySession如下:
private string UploadFileBySession(string url, byte[] file)
{
int fragSize = 1024 * 1024 * 4;
var arrayBatches = ByteArrayIntoBatches(file, fragSize);
int start = 0;
string response = "";
foreach (var byteArray in arrayBatches)
{
int byteArrayLength = byteArray.Length;
var contentRange = " bytes " + start + "-" + (start + (byteArrayLength - 1)) + "/" + file.Length;
using (var client = new HttpClient())
{
var content = new ByteArrayContent(byteArray);
content.Headers.Add("Content-Length", byteArrayLength.ToProperString());
content.Headers.Add("Content-Range", contentRange);
response = client.PutAsync(url, content).Result.Content.ReadAsStringAsync().Result;
}
start = start + byteArrayLength;
}
return response;
}
internal IEnumerable<byte[]> ByteArrayIntoBatches(byte[] bArray, int intBufforLengt)
{
int bArrayLenght = bArray.Length;
byte[] bReturn = null;
int i = 0;
for (; bArrayLenght > (i + 1) * intBufforLengt; i++)
{
bReturn = new byte[intBufforLengt];
Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLengt);
yield return bReturn;
}
int intBufforLeft = bArrayLenght - i * intBufforLengt;
if (intBufforLeft > 0)
{
bReturn = new byte[intBufforLeft];
Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLeft);
yield return bReturn;
}
}
UploadSessionResponse class 创建上传会话时反序列化 JSON 响应的文件
public class UploadSessionResponse
{
public string odatacontext { get; set; }
public DateTime expirationDateTime { get; set; }
public string[] nextExpectedRanges { get; set; }
public string uploadUrl { get; set; }
}
我正在尝试使用 Graph API 将文件上传到 OneDrive。当我上传小于 4MB 的文件时,下面的代码工作正常,但当我尝试上传大于 4MB 的文件时,它显示错误。我经历了 this documentation 但我仍然不确定如何才能完成这项工作。
下面是我对小于 4MB 的文件的工作代码。
using (var client = new HttpClient())
{
var url = "https://graph.microsoft.com/v1.0" + $"/drives/{driveID}/items/{folderId}:/{originalFileName}:/content";
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());
byte[] sContents = System.IO.File.ReadAllBytes(filePath);
var content = new ByteArrayContent(sContents);
var response = client.PutAsync(url, content).Result.Content.ReadAsStringAsync().Result;
}
请帮忙
对于大于 4MB 的文件,您需要 create an uploadSession 您 POST 此 URL:
https://graph.microsoft.com/v1.0/me/drive/root:/{item-path}:/createUploadSession
传递一组项目,
{
"item": {
"@odata.type": "microsoft.graph.driveItemUploadableProperties",
"@microsoft.graph.conflictBehavior": "rename",
"name": "largefile.dat"
}
}
我用的是"@microsoft.graph.conflictBehavior": "overwrite"
,而不是rename
。
响应会提供上传url批量上传文件
{
"uploadUrl": "https://sn3302.up.1drv.com/up/fe6987415ace7X4e1eF866337",
"expirationDateTime": "2015-01-29T09:21:55.523Z"
}
我没有 C# 示例,但这里有一个 PHP:
$url = $result['uploadUrl'];
$fragSize = 1024*1024*4;
$file = file_get_contents($source);
$fileSize = strlen($file);
$numFragments = ceil($fileSize / $fragSize);
$bytesRemaining = $fileSize;
$i = 0;
$response = null;
while ($i < $numFragments) {
$chunkSize = $numBytes = $fragSize;
$start = $i * $fragSize;
$end = $i * $fragSize + $chunkSize - 1;
$offset = $i * $fragSize;
if ($bytesRemaining < $chunkSize) {
$chunkSize = $numBytes = $bytesRemaining;
$end = $fileSize - 1;
}
if ($stream = fopen($source, 'r')) {
// get contents using offset
$data = stream_get_contents($stream, $chunkSize, $offset);
fclose($stream);
}
$contentRange = " bytes " . $start . "-" . $end . "/" . $fileSize;
$headers = array(
"Content-Length: $numBytes",
"Content-Range: $contentRange"
);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$server_output = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
$bytesRemaining = $bytesRemaining - $chunkSize;
$i++;
}
我们需要按长度(即 4MB)拆分字节数组并将它们传递给 OneDrive API。工作版本如下:
using (var client = new HttpClient())
{
var url = "https://graph.microsoft.com/v1.0" + $"/drives/{driveID}/items/{folderId}:/{originalFileName}:/createUploadSession";
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + GetAccessToken());
var sessionResponse = client.PostAsync(apiUrl, null).Result.Content.ReadAsStringAsync().Result;
byte[] sContents = System.IO.File.ReadAllBytes(filePath);
var uploadSession = JsonConvert.DeserializeObject<UploadSessionResponse>(sessionResponse);
string response = UploadFileBySession(uploadSession.uploadUrl, sContents);
}
UploadFileBySession如下:
private string UploadFileBySession(string url, byte[] file)
{
int fragSize = 1024 * 1024 * 4;
var arrayBatches = ByteArrayIntoBatches(file, fragSize);
int start = 0;
string response = "";
foreach (var byteArray in arrayBatches)
{
int byteArrayLength = byteArray.Length;
var contentRange = " bytes " + start + "-" + (start + (byteArrayLength - 1)) + "/" + file.Length;
using (var client = new HttpClient())
{
var content = new ByteArrayContent(byteArray);
content.Headers.Add("Content-Length", byteArrayLength.ToProperString());
content.Headers.Add("Content-Range", contentRange);
response = client.PutAsync(url, content).Result.Content.ReadAsStringAsync().Result;
}
start = start + byteArrayLength;
}
return response;
}
internal IEnumerable<byte[]> ByteArrayIntoBatches(byte[] bArray, int intBufforLengt)
{
int bArrayLenght = bArray.Length;
byte[] bReturn = null;
int i = 0;
for (; bArrayLenght > (i + 1) * intBufforLengt; i++)
{
bReturn = new byte[intBufforLengt];
Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLengt);
yield return bReturn;
}
int intBufforLeft = bArrayLenght - i * intBufforLengt;
if (intBufforLeft > 0)
{
bReturn = new byte[intBufforLeft];
Array.Copy(bArray, i * intBufforLengt, bReturn, 0, intBufforLeft);
yield return bReturn;
}
}
UploadSessionResponse class 创建上传会话时反序列化 JSON 响应的文件
public class UploadSessionResponse
{
public string odatacontext { get; set; }
public DateTime expirationDateTime { get; set; }
public string[] nextExpectedRanges { get; set; }
public string uploadUrl { get; set; }
}